The code and data behind xeiaso.net
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

pb: add mi definitions

Signed-off-by: Xe Iaso <me@xeiaso.net>

Xe Iaso d69787e5 4fe62fff

+2083 -54
+1 -1
internal/adminpb/internal.pb.go
··· 1 1 // Code generated by protoc-gen-go. DO NOT EDIT. 2 2 // versions: 3 3 // protoc-gen-go v1.32.0 4 - // protoc v4.24.4 4 + // protoc v5.26.1 5 5 // source: internal.proto 6 6 7 7 package adminpb
+1
pb/external/generate.go
··· 2 2 3 3 //go:generate protoc --proto_path=. --proto_path=.. --go_out=./protofeed --go_opt=paths=source_relative ./protofeed.proto 4 4 //go:generate protoc --proto_path=. --proto_path=.. --go_out=./mimi/announce --go_opt=paths=source_relative --twirp_out=./mimi/announce --twirp_opt=paths=source_relative ./mimi-announce.proto 5 + //go:generate protoc --proto_path=. --proto_path=.. --go_out=./mi --go_opt=paths=source_relative --twirp_out=./mi --twirp_opt=paths=source_relative ./mi.proto
+31
pb/external/mi.proto
··· 1 + // This is a subset of github:Xe/x/proto/mi.proto 2 + 3 + syntax = "proto3"; 4 + package within.website.x.mi; 5 + option go_package = "xeiaso.net/v4/pb/external/mi"; 6 + 7 + import "google/protobuf/timestamp.proto"; 8 + 9 + // Event is a single event that Xe will be attending. 10 + message Event { 11 + // The name of the event 12 + string name = 1; 13 + // The URL for the event 14 + string url = 2; 15 + // The day the event starts 16 + google.protobuf.Timestamp start_date = 3; 17 + // The day the event ends 18 + google.protobuf.Timestamp end_date = 4; 19 + // The location of the event (human-readable) 20 + string location = 5; 21 + // The ID of the event 22 + int32 id = 6; 23 + // The description of the event 24 + string description = 7; 25 + } 26 + 27 + // A feed of events, result from mi query. 28 + message EventFeed { 29 + // The events in the feed 30 + repeated Event events = 1; 31 + }
+290
pb/external/mi/mi.pb.go
··· 1 + // This is a subset of github:Xe/x/proto/mi.proto 2 + 3 + // Code generated by protoc-gen-go. DO NOT EDIT. 4 + // versions: 5 + // protoc-gen-go v1.32.0 6 + // protoc v5.26.1 7 + // source: mi.proto 8 + 9 + package mi 10 + 11 + import ( 12 + protoreflect "google.golang.org/protobuf/reflect/protoreflect" 13 + protoimpl "google.golang.org/protobuf/runtime/protoimpl" 14 + _ "google.golang.org/protobuf/types/known/emptypb" 15 + timestamppb "google.golang.org/protobuf/types/known/timestamppb" 16 + reflect "reflect" 17 + sync "sync" 18 + ) 19 + 20 + const ( 21 + // Verify that this generated code is sufficiently up-to-date. 22 + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 23 + // Verify that runtime/protoimpl is sufficiently up-to-date. 24 + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 25 + ) 26 + 27 + // Event is a single event that Xe will be attending. 28 + type Event struct { 29 + state protoimpl.MessageState 30 + sizeCache protoimpl.SizeCache 31 + unknownFields protoimpl.UnknownFields 32 + 33 + // The name of the event 34 + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 35 + // The URL for the event 36 + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` 37 + // The day the event starts 38 + StartDate *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=start_date,json=startDate,proto3" json:"start_date,omitempty"` 39 + // The day the event ends 40 + EndDate *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=end_date,json=endDate,proto3" json:"end_date,omitempty"` 41 + // The location of the event (human-readable) 42 + Location string `protobuf:"bytes,5,opt,name=location,proto3" json:"location,omitempty"` 43 + // The ID of the event 44 + Id int32 `protobuf:"varint,6,opt,name=id,proto3" json:"id,omitempty"` 45 + // The description of the event 46 + Description string `protobuf:"bytes,7,opt,name=description,proto3" json:"description,omitempty"` 47 + } 48 + 49 + func (x *Event) Reset() { 50 + *x = Event{} 51 + if protoimpl.UnsafeEnabled { 52 + mi := &file_mi_proto_msgTypes[0] 53 + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 54 + ms.StoreMessageInfo(mi) 55 + } 56 + } 57 + 58 + func (x *Event) String() string { 59 + return protoimpl.X.MessageStringOf(x) 60 + } 61 + 62 + func (*Event) ProtoMessage() {} 63 + 64 + func (x *Event) ProtoReflect() protoreflect.Message { 65 + mi := &file_mi_proto_msgTypes[0] 66 + if protoimpl.UnsafeEnabled && x != nil { 67 + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 68 + if ms.LoadMessageInfo() == nil { 69 + ms.StoreMessageInfo(mi) 70 + } 71 + return ms 72 + } 73 + return mi.MessageOf(x) 74 + } 75 + 76 + // Deprecated: Use Event.ProtoReflect.Descriptor instead. 77 + func (*Event) Descriptor() ([]byte, []int) { 78 + return file_mi_proto_rawDescGZIP(), []int{0} 79 + } 80 + 81 + func (x *Event) GetName() string { 82 + if x != nil { 83 + return x.Name 84 + } 85 + return "" 86 + } 87 + 88 + func (x *Event) GetUrl() string { 89 + if x != nil { 90 + return x.Url 91 + } 92 + return "" 93 + } 94 + 95 + func (x *Event) GetStartDate() *timestamppb.Timestamp { 96 + if x != nil { 97 + return x.StartDate 98 + } 99 + return nil 100 + } 101 + 102 + func (x *Event) GetEndDate() *timestamppb.Timestamp { 103 + if x != nil { 104 + return x.EndDate 105 + } 106 + return nil 107 + } 108 + 109 + func (x *Event) GetLocation() string { 110 + if x != nil { 111 + return x.Location 112 + } 113 + return "" 114 + } 115 + 116 + func (x *Event) GetId() int32 { 117 + if x != nil { 118 + return x.Id 119 + } 120 + return 0 121 + } 122 + 123 + func (x *Event) GetDescription() string { 124 + if x != nil { 125 + return x.Description 126 + } 127 + return "" 128 + } 129 + 130 + // A feed of events, result from mi query. 131 + type EventFeed struct { 132 + state protoimpl.MessageState 133 + sizeCache protoimpl.SizeCache 134 + unknownFields protoimpl.UnknownFields 135 + 136 + // The events in the feed 137 + Events []*Event `protobuf:"bytes,1,rep,name=events,proto3" json:"events,omitempty"` 138 + } 139 + 140 + func (x *EventFeed) Reset() { 141 + *x = EventFeed{} 142 + if protoimpl.UnsafeEnabled { 143 + mi := &file_mi_proto_msgTypes[1] 144 + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 145 + ms.StoreMessageInfo(mi) 146 + } 147 + } 148 + 149 + func (x *EventFeed) String() string { 150 + return protoimpl.X.MessageStringOf(x) 151 + } 152 + 153 + func (*EventFeed) ProtoMessage() {} 154 + 155 + func (x *EventFeed) ProtoReflect() protoreflect.Message { 156 + mi := &file_mi_proto_msgTypes[1] 157 + if protoimpl.UnsafeEnabled && x != nil { 158 + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 159 + if ms.LoadMessageInfo() == nil { 160 + ms.StoreMessageInfo(mi) 161 + } 162 + return ms 163 + } 164 + return mi.MessageOf(x) 165 + } 166 + 167 + // Deprecated: Use EventFeed.ProtoReflect.Descriptor instead. 168 + func (*EventFeed) Descriptor() ([]byte, []int) { 169 + return file_mi_proto_rawDescGZIP(), []int{1} 170 + } 171 + 172 + func (x *EventFeed) GetEvents() []*Event { 173 + if x != nil { 174 + return x.Events 175 + } 176 + return nil 177 + } 178 + 179 + var File_mi_proto protoreflect.FileDescriptor 180 + 181 + var file_mi_proto_rawDesc = []byte{ 182 + 0x0a, 0x08, 0x6d, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x77, 0x69, 0x74, 0x68, 183 + 0x69, 0x6e, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x2e, 0x78, 0x2e, 0x6d, 0x69, 0x1a, 184 + 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 185 + 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 186 + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 187 + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xed, 0x01, 188 + 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 189 + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 190 + 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x39, 0x0a, 191 + 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 192 + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 193 + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x73, 194 + 0x74, 0x61, 0x72, 0x74, 0x44, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 195 + 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 196 + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 197 + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 198 + 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 199 + 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 200 + 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x64, 201 + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 202 + 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3f, 0x0a, 203 + 0x09, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x46, 0x65, 0x65, 0x64, 0x12, 0x32, 0x0a, 0x06, 0x65, 0x76, 204 + 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x77, 0x69, 0x74, 205 + 0x68, 0x69, 0x6e, 0x2e, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x2e, 0x78, 0x2e, 0x6d, 0x69, 206 + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x42, 0x1e, 207 + 0x5a, 0x1c, 0x78, 0x65, 0x69, 0x61, 0x73, 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x34, 0x2f, 208 + 0x70, 0x62, 0x2f, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x6d, 0x69, 0x62, 0x06, 209 + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 210 + } 211 + 212 + var ( 213 + file_mi_proto_rawDescOnce sync.Once 214 + file_mi_proto_rawDescData = file_mi_proto_rawDesc 215 + ) 216 + 217 + func file_mi_proto_rawDescGZIP() []byte { 218 + file_mi_proto_rawDescOnce.Do(func() { 219 + file_mi_proto_rawDescData = protoimpl.X.CompressGZIP(file_mi_proto_rawDescData) 220 + }) 221 + return file_mi_proto_rawDescData 222 + } 223 + 224 + var file_mi_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 225 + var file_mi_proto_goTypes = []interface{}{ 226 + (*Event)(nil), // 0: within.website.x.mi.Event 227 + (*EventFeed)(nil), // 1: within.website.x.mi.EventFeed 228 + (*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp 229 + } 230 + var file_mi_proto_depIdxs = []int32{ 231 + 2, // 0: within.website.x.mi.Event.start_date:type_name -> google.protobuf.Timestamp 232 + 2, // 1: within.website.x.mi.Event.end_date:type_name -> google.protobuf.Timestamp 233 + 0, // 2: within.website.x.mi.EventFeed.events:type_name -> within.website.x.mi.Event 234 + 3, // [3:3] is the sub-list for method output_type 235 + 3, // [3:3] is the sub-list for method input_type 236 + 3, // [3:3] is the sub-list for extension type_name 237 + 3, // [3:3] is the sub-list for extension extendee 238 + 0, // [0:3] is the sub-list for field type_name 239 + } 240 + 241 + func init() { file_mi_proto_init() } 242 + func file_mi_proto_init() { 243 + if File_mi_proto != nil { 244 + return 245 + } 246 + if !protoimpl.UnsafeEnabled { 247 + file_mi_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 248 + switch v := v.(*Event); i { 249 + case 0: 250 + return &v.state 251 + case 1: 252 + return &v.sizeCache 253 + case 2: 254 + return &v.unknownFields 255 + default: 256 + return nil 257 + } 258 + } 259 + file_mi_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 260 + switch v := v.(*EventFeed); i { 261 + case 0: 262 + return &v.state 263 + case 1: 264 + return &v.sizeCache 265 + case 2: 266 + return &v.unknownFields 267 + default: 268 + return nil 269 + } 270 + } 271 + } 272 + type x struct{} 273 + out := protoimpl.TypeBuilder{ 274 + File: protoimpl.DescBuilder{ 275 + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 276 + RawDescriptor: file_mi_proto_rawDesc, 277 + NumEnums: 0, 278 + NumMessages: 2, 279 + NumExtensions: 0, 280 + NumServices: 0, 281 + }, 282 + GoTypes: file_mi_proto_goTypes, 283 + DependencyIndexes: file_mi_proto_depIdxs, 284 + MessageInfos: file_mi_proto_msgTypes, 285 + }.Build() 286 + File_mi_proto = out.File 287 + file_mi_proto_rawDesc = nil 288 + file_mi_proto_goTypes = nil 289 + file_mi_proto_depIdxs = nil 290 + }
+1115
pb/external/mi/mi.twirp.go
··· 1 + // Code generated by protoc-gen-twirp v8.1.3, DO NOT EDIT. 2 + // source: mi.proto 3 + 4 + package mi 5 + 6 + import context "context" 7 + import fmt "fmt" 8 + import http "net/http" 9 + import io "io" 10 + import json "encoding/json" 11 + import strconv "strconv" 12 + import strings "strings" 13 + 14 + import protojson "google.golang.org/protobuf/encoding/protojson" 15 + import proto "google.golang.org/protobuf/proto" 16 + import twirp "github.com/twitchtv/twirp" 17 + import ctxsetters "github.com/twitchtv/twirp/ctxsetters" 18 + 19 + import google_protobuf "google.golang.org/protobuf/types/known/emptypb" 20 + 21 + import bytes "bytes" 22 + import errors "errors" 23 + import path "path" 24 + import url "net/url" 25 + 26 + // Version compatibility assertion. 27 + // If the constant is not defined in the package, that likely means 28 + // the package needs to be updated to work with this generated code. 29 + // See https://twitchtv.github.io/twirp/docs/version_matrix.html 30 + const _ = twirp.TwirpPackageMinVersion_8_1_0 31 + 32 + // ================ 33 + // Events Interface 34 + // ================ 35 + 36 + // Events lets users fetch the current feed of events that Xe will be attending. 37 + type Events interface { 38 + // Get fetches the current feed of upcoming events. 39 + Get(context.Context, *google_protobuf.Empty) (*EventFeed, error) 40 + } 41 + 42 + // ====================== 43 + // Events Protobuf Client 44 + // ====================== 45 + 46 + type eventsProtobufClient struct { 47 + client HTTPClient 48 + urls [1]string 49 + interceptor twirp.Interceptor 50 + opts twirp.ClientOptions 51 + } 52 + 53 + // NewEventsProtobufClient creates a Protobuf client that implements the Events interface. 54 + // It communicates using Protobuf and can be configured with a custom HTTPClient. 55 + func NewEventsProtobufClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) Events { 56 + if c, ok := client.(*http.Client); ok { 57 + client = withoutRedirects(c) 58 + } 59 + 60 + clientOpts := twirp.ClientOptions{} 61 + for _, o := range opts { 62 + o(&clientOpts) 63 + } 64 + 65 + // Using ReadOpt allows backwards and forwards compatibility with new options in the future 66 + literalURLs := false 67 + _ = clientOpts.ReadOpt("literalURLs", &literalURLs) 68 + var pathPrefix string 69 + if ok := clientOpts.ReadOpt("pathPrefix", &pathPrefix); !ok { 70 + pathPrefix = "/twirp" // default prefix 71 + } 72 + 73 + // Build method URLs: <baseURL>[<prefix>]/<package>.<Service>/<Method> 74 + serviceURL := sanitizeBaseURL(baseURL) 75 + serviceURL += baseServicePath(pathPrefix, "within.website.x.mi", "Events") 76 + urls := [1]string{ 77 + serviceURL + "Get", 78 + } 79 + 80 + return &eventsProtobufClient{ 81 + client: client, 82 + urls: urls, 83 + interceptor: twirp.ChainInterceptors(clientOpts.Interceptors...), 84 + opts: clientOpts, 85 + } 86 + } 87 + 88 + func (c *eventsProtobufClient) Get(ctx context.Context, in *google_protobuf.Empty) (*EventFeed, error) { 89 + ctx = ctxsetters.WithPackageName(ctx, "within.website.x.mi") 90 + ctx = ctxsetters.WithServiceName(ctx, "Events") 91 + ctx = ctxsetters.WithMethodName(ctx, "Get") 92 + caller := c.callGet 93 + if c.interceptor != nil { 94 + caller = func(ctx context.Context, req *google_protobuf.Empty) (*EventFeed, error) { 95 + resp, err := c.interceptor( 96 + func(ctx context.Context, req interface{}) (interface{}, error) { 97 + typedReq, ok := req.(*google_protobuf.Empty) 98 + if !ok { 99 + return nil, twirp.InternalError("failed type assertion req.(*google_protobuf.Empty) when calling interceptor") 100 + } 101 + return c.callGet(ctx, typedReq) 102 + }, 103 + )(ctx, req) 104 + if resp != nil { 105 + typedResp, ok := resp.(*EventFeed) 106 + if !ok { 107 + return nil, twirp.InternalError("failed type assertion resp.(*EventFeed) when calling interceptor") 108 + } 109 + return typedResp, err 110 + } 111 + return nil, err 112 + } 113 + } 114 + return caller(ctx, in) 115 + } 116 + 117 + func (c *eventsProtobufClient) callGet(ctx context.Context, in *google_protobuf.Empty) (*EventFeed, error) { 118 + out := new(EventFeed) 119 + ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) 120 + if err != nil { 121 + twerr, ok := err.(twirp.Error) 122 + if !ok { 123 + twerr = twirp.InternalErrorWith(err) 124 + } 125 + callClientError(ctx, c.opts.Hooks, twerr) 126 + return nil, err 127 + } 128 + 129 + callClientResponseReceived(ctx, c.opts.Hooks) 130 + 131 + return out, nil 132 + } 133 + 134 + // ================== 135 + // Events JSON Client 136 + // ================== 137 + 138 + type eventsJSONClient struct { 139 + client HTTPClient 140 + urls [1]string 141 + interceptor twirp.Interceptor 142 + opts twirp.ClientOptions 143 + } 144 + 145 + // NewEventsJSONClient creates a JSON client that implements the Events interface. 146 + // It communicates using JSON and can be configured with a custom HTTPClient. 147 + func NewEventsJSONClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) Events { 148 + if c, ok := client.(*http.Client); ok { 149 + client = withoutRedirects(c) 150 + } 151 + 152 + clientOpts := twirp.ClientOptions{} 153 + for _, o := range opts { 154 + o(&clientOpts) 155 + } 156 + 157 + // Using ReadOpt allows backwards and forwards compatibility with new options in the future 158 + literalURLs := false 159 + _ = clientOpts.ReadOpt("literalURLs", &literalURLs) 160 + var pathPrefix string 161 + if ok := clientOpts.ReadOpt("pathPrefix", &pathPrefix); !ok { 162 + pathPrefix = "/twirp" // default prefix 163 + } 164 + 165 + // Build method URLs: <baseURL>[<prefix>]/<package>.<Service>/<Method> 166 + serviceURL := sanitizeBaseURL(baseURL) 167 + serviceURL += baseServicePath(pathPrefix, "within.website.x.mi", "Events") 168 + urls := [1]string{ 169 + serviceURL + "Get", 170 + } 171 + 172 + return &eventsJSONClient{ 173 + client: client, 174 + urls: urls, 175 + interceptor: twirp.ChainInterceptors(clientOpts.Interceptors...), 176 + opts: clientOpts, 177 + } 178 + } 179 + 180 + func (c *eventsJSONClient) Get(ctx context.Context, in *google_protobuf.Empty) (*EventFeed, error) { 181 + ctx = ctxsetters.WithPackageName(ctx, "within.website.x.mi") 182 + ctx = ctxsetters.WithServiceName(ctx, "Events") 183 + ctx = ctxsetters.WithMethodName(ctx, "Get") 184 + caller := c.callGet 185 + if c.interceptor != nil { 186 + caller = func(ctx context.Context, req *google_protobuf.Empty) (*EventFeed, error) { 187 + resp, err := c.interceptor( 188 + func(ctx context.Context, req interface{}) (interface{}, error) { 189 + typedReq, ok := req.(*google_protobuf.Empty) 190 + if !ok { 191 + return nil, twirp.InternalError("failed type assertion req.(*google_protobuf.Empty) when calling interceptor") 192 + } 193 + return c.callGet(ctx, typedReq) 194 + }, 195 + )(ctx, req) 196 + if resp != nil { 197 + typedResp, ok := resp.(*EventFeed) 198 + if !ok { 199 + return nil, twirp.InternalError("failed type assertion resp.(*EventFeed) when calling interceptor") 200 + } 201 + return typedResp, err 202 + } 203 + return nil, err 204 + } 205 + } 206 + return caller(ctx, in) 207 + } 208 + 209 + func (c *eventsJSONClient) callGet(ctx context.Context, in *google_protobuf.Empty) (*EventFeed, error) { 210 + out := new(EventFeed) 211 + ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) 212 + if err != nil { 213 + twerr, ok := err.(twirp.Error) 214 + if !ok { 215 + twerr = twirp.InternalErrorWith(err) 216 + } 217 + callClientError(ctx, c.opts.Hooks, twerr) 218 + return nil, err 219 + } 220 + 221 + callClientResponseReceived(ctx, c.opts.Hooks) 222 + 223 + return out, nil 224 + } 225 + 226 + // ===================== 227 + // Events Server Handler 228 + // ===================== 229 + 230 + type eventsServer struct { 231 + Events 232 + interceptor twirp.Interceptor 233 + hooks *twirp.ServerHooks 234 + pathPrefix string // prefix for routing 235 + jsonSkipDefaults bool // do not include unpopulated fields (default values) in the response 236 + jsonCamelCase bool // JSON fields are serialized as lowerCamelCase rather than keeping the original proto names 237 + } 238 + 239 + // NewEventsServer builds a TwirpServer that can be used as an http.Handler to handle 240 + // HTTP requests that are routed to the right method in the provided svc implementation. 241 + // The opts are twirp.ServerOption modifiers, for example twirp.WithServerHooks(hooks). 242 + func NewEventsServer(svc Events, opts ...interface{}) TwirpServer { 243 + serverOpts := newServerOpts(opts) 244 + 245 + // Using ReadOpt allows backwards and forwards compatibility with new options in the future 246 + jsonSkipDefaults := false 247 + _ = serverOpts.ReadOpt("jsonSkipDefaults", &jsonSkipDefaults) 248 + jsonCamelCase := false 249 + _ = serverOpts.ReadOpt("jsonCamelCase", &jsonCamelCase) 250 + var pathPrefix string 251 + if ok := serverOpts.ReadOpt("pathPrefix", &pathPrefix); !ok { 252 + pathPrefix = "/twirp" // default prefix 253 + } 254 + 255 + return &eventsServer{ 256 + Events: svc, 257 + hooks: serverOpts.Hooks, 258 + interceptor: twirp.ChainInterceptors(serverOpts.Interceptors...), 259 + pathPrefix: pathPrefix, 260 + jsonSkipDefaults: jsonSkipDefaults, 261 + jsonCamelCase: jsonCamelCase, 262 + } 263 + } 264 + 265 + // writeError writes an HTTP response with a valid Twirp error format, and triggers hooks. 266 + // If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err) 267 + func (s *eventsServer) writeError(ctx context.Context, resp http.ResponseWriter, err error) { 268 + writeError(ctx, resp, err, s.hooks) 269 + } 270 + 271 + // handleRequestBodyError is used to handle error when the twirp server cannot read request 272 + func (s *eventsServer) handleRequestBodyError(ctx context.Context, resp http.ResponseWriter, msg string, err error) { 273 + if context.Canceled == ctx.Err() { 274 + s.writeError(ctx, resp, twirp.NewError(twirp.Canceled, "failed to read request: context canceled")) 275 + return 276 + } 277 + if context.DeadlineExceeded == ctx.Err() { 278 + s.writeError(ctx, resp, twirp.NewError(twirp.DeadlineExceeded, "failed to read request: deadline exceeded")) 279 + return 280 + } 281 + s.writeError(ctx, resp, twirp.WrapError(malformedRequestError(msg), err)) 282 + } 283 + 284 + // EventsPathPrefix is a convenience constant that may identify URL paths. 285 + // Should be used with caution, it only matches routes generated by Twirp Go clients, 286 + // with the default "/twirp" prefix and default CamelCase service and method names. 287 + // More info: https://twitchtv.github.io/twirp/docs/routing.html 288 + const EventsPathPrefix = "/twirp/within.website.x.mi.Events/" 289 + 290 + func (s *eventsServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) { 291 + ctx := req.Context() 292 + ctx = ctxsetters.WithPackageName(ctx, "within.website.x.mi") 293 + ctx = ctxsetters.WithServiceName(ctx, "Events") 294 + ctx = ctxsetters.WithResponseWriter(ctx, resp) 295 + 296 + var err error 297 + ctx, err = callRequestReceived(ctx, s.hooks) 298 + if err != nil { 299 + s.writeError(ctx, resp, err) 300 + return 301 + } 302 + 303 + if req.Method != "POST" { 304 + msg := fmt.Sprintf("unsupported method %q (only POST is allowed)", req.Method) 305 + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) 306 + return 307 + } 308 + 309 + // Verify path format: [<prefix>]/<package>.<Service>/<Method> 310 + prefix, pkgService, method := parseTwirpPath(req.URL.Path) 311 + if pkgService != "within.website.x.mi.Events" { 312 + msg := fmt.Sprintf("no handler for path %q", req.URL.Path) 313 + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) 314 + return 315 + } 316 + if prefix != s.pathPrefix { 317 + msg := fmt.Sprintf("invalid path prefix %q, expected %q, on path %q", prefix, s.pathPrefix, req.URL.Path) 318 + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) 319 + return 320 + } 321 + 322 + switch method { 323 + case "Get": 324 + s.serveGet(ctx, resp, req) 325 + return 326 + default: 327 + msg := fmt.Sprintf("no handler for path %q", req.URL.Path) 328 + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) 329 + return 330 + } 331 + } 332 + 333 + func (s *eventsServer) serveGet(ctx context.Context, resp http.ResponseWriter, req *http.Request) { 334 + header := req.Header.Get("Content-Type") 335 + i := strings.Index(header, ";") 336 + if i == -1 { 337 + i = len(header) 338 + } 339 + switch strings.TrimSpace(strings.ToLower(header[:i])) { 340 + case "application/json": 341 + s.serveGetJSON(ctx, resp, req) 342 + case "application/protobuf": 343 + s.serveGetProtobuf(ctx, resp, req) 344 + default: 345 + msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")) 346 + twerr := badRouteError(msg, req.Method, req.URL.Path) 347 + s.writeError(ctx, resp, twerr) 348 + } 349 + } 350 + 351 + func (s *eventsServer) serveGetJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) { 352 + var err error 353 + ctx = ctxsetters.WithMethodName(ctx, "Get") 354 + ctx, err = callRequestRouted(ctx, s.hooks) 355 + if err != nil { 356 + s.writeError(ctx, resp, err) 357 + return 358 + } 359 + 360 + d := json.NewDecoder(req.Body) 361 + rawReqBody := json.RawMessage{} 362 + if err := d.Decode(&rawReqBody); err != nil { 363 + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) 364 + return 365 + } 366 + reqContent := new(google_protobuf.Empty) 367 + unmarshaler := protojson.UnmarshalOptions{DiscardUnknown: true} 368 + if err = unmarshaler.Unmarshal(rawReqBody, reqContent); err != nil { 369 + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) 370 + return 371 + } 372 + 373 + handler := s.Events.Get 374 + if s.interceptor != nil { 375 + handler = func(ctx context.Context, req *google_protobuf.Empty) (*EventFeed, error) { 376 + resp, err := s.interceptor( 377 + func(ctx context.Context, req interface{}) (interface{}, error) { 378 + typedReq, ok := req.(*google_protobuf.Empty) 379 + if !ok { 380 + return nil, twirp.InternalError("failed type assertion req.(*google_protobuf.Empty) when calling interceptor") 381 + } 382 + return s.Events.Get(ctx, typedReq) 383 + }, 384 + )(ctx, req) 385 + if resp != nil { 386 + typedResp, ok := resp.(*EventFeed) 387 + if !ok { 388 + return nil, twirp.InternalError("failed type assertion resp.(*EventFeed) when calling interceptor") 389 + } 390 + return typedResp, err 391 + } 392 + return nil, err 393 + } 394 + } 395 + 396 + // Call service method 397 + var respContent *EventFeed 398 + func() { 399 + defer ensurePanicResponses(ctx, resp, s.hooks) 400 + respContent, err = handler(ctx, reqContent) 401 + }() 402 + 403 + if err != nil { 404 + s.writeError(ctx, resp, err) 405 + return 406 + } 407 + if respContent == nil { 408 + s.writeError(ctx, resp, twirp.InternalError("received a nil *EventFeed and nil error while calling Get. nil responses are not supported")) 409 + return 410 + } 411 + 412 + ctx = callResponsePrepared(ctx, s.hooks) 413 + 414 + marshaler := &protojson.MarshalOptions{UseProtoNames: !s.jsonCamelCase, EmitUnpopulated: !s.jsonSkipDefaults} 415 + respBytes, err := marshaler.Marshal(respContent) 416 + if err != nil { 417 + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal json response")) 418 + return 419 + } 420 + 421 + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) 422 + resp.Header().Set("Content-Type", "application/json") 423 + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) 424 + resp.WriteHeader(http.StatusOK) 425 + 426 + if n, err := resp.Write(respBytes); err != nil { 427 + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) 428 + twerr := twirp.NewError(twirp.Unknown, msg) 429 + ctx = callError(ctx, s.hooks, twerr) 430 + } 431 + callResponseSent(ctx, s.hooks) 432 + } 433 + 434 + func (s *eventsServer) serveGetProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) { 435 + var err error 436 + ctx = ctxsetters.WithMethodName(ctx, "Get") 437 + ctx, err = callRequestRouted(ctx, s.hooks) 438 + if err != nil { 439 + s.writeError(ctx, resp, err) 440 + return 441 + } 442 + 443 + buf, err := io.ReadAll(req.Body) 444 + if err != nil { 445 + s.handleRequestBodyError(ctx, resp, "failed to read request body", err) 446 + return 447 + } 448 + reqContent := new(google_protobuf.Empty) 449 + if err = proto.Unmarshal(buf, reqContent); err != nil { 450 + s.writeError(ctx, resp, malformedRequestError("the protobuf request could not be decoded")) 451 + return 452 + } 453 + 454 + handler := s.Events.Get 455 + if s.interceptor != nil { 456 + handler = func(ctx context.Context, req *google_protobuf.Empty) (*EventFeed, error) { 457 + resp, err := s.interceptor( 458 + func(ctx context.Context, req interface{}) (interface{}, error) { 459 + typedReq, ok := req.(*google_protobuf.Empty) 460 + if !ok { 461 + return nil, twirp.InternalError("failed type assertion req.(*google_protobuf.Empty) when calling interceptor") 462 + } 463 + return s.Events.Get(ctx, typedReq) 464 + }, 465 + )(ctx, req) 466 + if resp != nil { 467 + typedResp, ok := resp.(*EventFeed) 468 + if !ok { 469 + return nil, twirp.InternalError("failed type assertion resp.(*EventFeed) when calling interceptor") 470 + } 471 + return typedResp, err 472 + } 473 + return nil, err 474 + } 475 + } 476 + 477 + // Call service method 478 + var respContent *EventFeed 479 + func() { 480 + defer ensurePanicResponses(ctx, resp, s.hooks) 481 + respContent, err = handler(ctx, reqContent) 482 + }() 483 + 484 + if err != nil { 485 + s.writeError(ctx, resp, err) 486 + return 487 + } 488 + if respContent == nil { 489 + s.writeError(ctx, resp, twirp.InternalError("received a nil *EventFeed and nil error while calling Get. nil responses are not supported")) 490 + return 491 + } 492 + 493 + ctx = callResponsePrepared(ctx, s.hooks) 494 + 495 + respBytes, err := proto.Marshal(respContent) 496 + if err != nil { 497 + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal proto response")) 498 + return 499 + } 500 + 501 + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) 502 + resp.Header().Set("Content-Type", "application/protobuf") 503 + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) 504 + resp.WriteHeader(http.StatusOK) 505 + if n, err := resp.Write(respBytes); err != nil { 506 + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) 507 + twerr := twirp.NewError(twirp.Unknown, msg) 508 + ctx = callError(ctx, s.hooks, twerr) 509 + } 510 + callResponseSent(ctx, s.hooks) 511 + } 512 + 513 + func (s *eventsServer) ServiceDescriptor() ([]byte, int) { 514 + return twirpFileDescriptor0, 0 515 + } 516 + 517 + func (s *eventsServer) ProtocGenTwirpVersion() string { 518 + return "v8.1.3" 519 + } 520 + 521 + // PathPrefix returns the base service path, in the form: "/<prefix>/<package>.<Service>/" 522 + // that is everything in a Twirp route except for the <Method>. This can be used for routing, 523 + // for example to identify the requests that are targeted to this service in a mux. 524 + func (s *eventsServer) PathPrefix() string { 525 + return baseServicePath(s.pathPrefix, "within.website.x.mi", "Events") 526 + } 527 + 528 + // ===== 529 + // Utils 530 + // ===== 531 + 532 + // HTTPClient is the interface used by generated clients to send HTTP requests. 533 + // It is fulfilled by *(net/http).Client, which is sufficient for most users. 534 + // Users can provide their own implementation for special retry policies. 535 + // 536 + // HTTPClient implementations should not follow redirects. Redirects are 537 + // automatically disabled if *(net/http).Client is passed to client 538 + // constructors. See the withoutRedirects function in this file for more 539 + // details. 540 + type HTTPClient interface { 541 + Do(req *http.Request) (*http.Response, error) 542 + } 543 + 544 + // TwirpServer is the interface generated server structs will support: they're 545 + // HTTP handlers with additional methods for accessing metadata about the 546 + // service. Those accessors are a low-level API for building reflection tools. 547 + // Most people can think of TwirpServers as just http.Handlers. 548 + type TwirpServer interface { 549 + http.Handler 550 + 551 + // ServiceDescriptor returns gzipped bytes describing the .proto file that 552 + // this service was generated from. Once unzipped, the bytes can be 553 + // unmarshalled as a 554 + // google.golang.org/protobuf/types/descriptorpb.FileDescriptorProto. 555 + // 556 + // The returned integer is the index of this particular service within that 557 + // FileDescriptorProto's 'Service' slice of ServiceDescriptorProtos. This is a 558 + // low-level field, expected to be used for reflection. 559 + ServiceDescriptor() ([]byte, int) 560 + 561 + // ProtocGenTwirpVersion is the semantic version string of the version of 562 + // twirp used to generate this file. 563 + ProtocGenTwirpVersion() string 564 + 565 + // PathPrefix returns the HTTP URL path prefix for all methods handled by this 566 + // service. This can be used with an HTTP mux to route Twirp requests. 567 + // The path prefix is in the form: "/<prefix>/<package>.<Service>/" 568 + // that is, everything in a Twirp route except for the <Method> at the end. 569 + PathPrefix() string 570 + } 571 + 572 + func newServerOpts(opts []interface{}) *twirp.ServerOptions { 573 + serverOpts := &twirp.ServerOptions{} 574 + for _, opt := range opts { 575 + switch o := opt.(type) { 576 + case twirp.ServerOption: 577 + o(serverOpts) 578 + case *twirp.ServerHooks: // backwards compatibility, allow to specify hooks as an argument 579 + twirp.WithServerHooks(o)(serverOpts) 580 + case nil: // backwards compatibility, allow nil value for the argument 581 + continue 582 + default: 583 + panic(fmt.Sprintf("Invalid option type %T, please use a twirp.ServerOption", o)) 584 + } 585 + } 586 + return serverOpts 587 + } 588 + 589 + // WriteError writes an HTTP response with a valid Twirp error format (code, msg, meta). 590 + // Useful outside of the Twirp server (e.g. http middleware), but does not trigger hooks. 591 + // If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err) 592 + func WriteError(resp http.ResponseWriter, err error) { 593 + writeError(context.Background(), resp, err, nil) 594 + } 595 + 596 + // writeError writes Twirp errors in the response and triggers hooks. 597 + func writeError(ctx context.Context, resp http.ResponseWriter, err error, hooks *twirp.ServerHooks) { 598 + // Convert to a twirp.Error. Non-twirp errors are converted to internal errors. 599 + var twerr twirp.Error 600 + if !errors.As(err, &twerr) { 601 + twerr = twirp.InternalErrorWith(err) 602 + } 603 + 604 + statusCode := twirp.ServerHTTPStatusFromErrorCode(twerr.Code()) 605 + ctx = ctxsetters.WithStatusCode(ctx, statusCode) 606 + ctx = callError(ctx, hooks, twerr) 607 + 608 + respBody := marshalErrorToJSON(twerr) 609 + 610 + resp.Header().Set("Content-Type", "application/json") // Error responses are always JSON 611 + resp.Header().Set("Content-Length", strconv.Itoa(len(respBody))) 612 + resp.WriteHeader(statusCode) // set HTTP status code and send response 613 + 614 + _, writeErr := resp.Write(respBody) 615 + if writeErr != nil { 616 + // We have three options here. We could log the error, call the Error 617 + // hook, or just silently ignore the error. 618 + // 619 + // Logging is unacceptable because we don't have a user-controlled 620 + // logger; writing out to stderr without permission is too rude. 621 + // 622 + // Calling the Error hook would confuse users: it would mean the Error 623 + // hook got called twice for one request, which is likely to lead to 624 + // duplicated log messages and metrics, no matter how well we document 625 + // the behavior. 626 + // 627 + // Silently ignoring the error is our least-bad option. It's highly 628 + // likely that the connection is broken and the original 'err' says 629 + // so anyway. 630 + _ = writeErr 631 + } 632 + 633 + callResponseSent(ctx, hooks) 634 + } 635 + 636 + // sanitizeBaseURL parses the the baseURL, and adds the "http" scheme if needed. 637 + // If the URL is unparsable, the baseURL is returned unchanged. 638 + func sanitizeBaseURL(baseURL string) string { 639 + u, err := url.Parse(baseURL) 640 + if err != nil { 641 + return baseURL // invalid URL will fail later when making requests 642 + } 643 + if u.Scheme == "" { 644 + u.Scheme = "http" 645 + } 646 + return u.String() 647 + } 648 + 649 + // baseServicePath composes the path prefix for the service (without <Method>). 650 + // e.g.: baseServicePath("/twirp", "my.pkg", "MyService") 651 + // 652 + // returns => "/twirp/my.pkg.MyService/" 653 + // 654 + // e.g.: baseServicePath("", "", "MyService") 655 + // 656 + // returns => "/MyService/" 657 + func baseServicePath(prefix, pkg, service string) string { 658 + fullServiceName := service 659 + if pkg != "" { 660 + fullServiceName = pkg + "." + service 661 + } 662 + return path.Join("/", prefix, fullServiceName) + "/" 663 + } 664 + 665 + // parseTwirpPath extracts path components form a valid Twirp route. 666 + // Expected format: "[<prefix>]/<package>.<Service>/<Method>" 667 + // e.g.: prefix, pkgService, method := parseTwirpPath("/twirp/pkg.Svc/MakeHat") 668 + func parseTwirpPath(path string) (string, string, string) { 669 + parts := strings.Split(path, "/") 670 + if len(parts) < 2 { 671 + return "", "", "" 672 + } 673 + method := parts[len(parts)-1] 674 + pkgService := parts[len(parts)-2] 675 + prefix := strings.Join(parts[0:len(parts)-2], "/") 676 + return prefix, pkgService, method 677 + } 678 + 679 + // getCustomHTTPReqHeaders retrieves a copy of any headers that are set in 680 + // a context through the twirp.WithHTTPRequestHeaders function. 681 + // If there are no headers set, or if they have the wrong type, nil is returned. 682 + func getCustomHTTPReqHeaders(ctx context.Context) http.Header { 683 + header, ok := twirp.HTTPRequestHeaders(ctx) 684 + if !ok || header == nil { 685 + return nil 686 + } 687 + copied := make(http.Header) 688 + for k, vv := range header { 689 + if vv == nil { 690 + copied[k] = nil 691 + continue 692 + } 693 + copied[k] = make([]string, len(vv)) 694 + copy(copied[k], vv) 695 + } 696 + return copied 697 + } 698 + 699 + // newRequest makes an http.Request from a client, adding common headers. 700 + func newRequest(ctx context.Context, url string, reqBody io.Reader, contentType string) (*http.Request, error) { 701 + req, err := http.NewRequest("POST", url, reqBody) 702 + if err != nil { 703 + return nil, err 704 + } 705 + req = req.WithContext(ctx) 706 + if customHeader := getCustomHTTPReqHeaders(ctx); customHeader != nil { 707 + req.Header = customHeader 708 + } 709 + req.Header.Set("Accept", contentType) 710 + req.Header.Set("Content-Type", contentType) 711 + req.Header.Set("Twirp-Version", "v8.1.3") 712 + return req, nil 713 + } 714 + 715 + // JSON serialization for errors 716 + type twerrJSON struct { 717 + Code string `json:"code"` 718 + Msg string `json:"msg"` 719 + Meta map[string]string `json:"meta,omitempty"` 720 + } 721 + 722 + // marshalErrorToJSON returns JSON from a twirp.Error, that can be used as HTTP error response body. 723 + // If serialization fails, it will use a descriptive Internal error instead. 724 + func marshalErrorToJSON(twerr twirp.Error) []byte { 725 + // make sure that msg is not too large 726 + msg := twerr.Msg() 727 + if len(msg) > 1e6 { 728 + msg = msg[:1e6] 729 + } 730 + 731 + tj := twerrJSON{ 732 + Code: string(twerr.Code()), 733 + Msg: msg, 734 + Meta: twerr.MetaMap(), 735 + } 736 + 737 + buf, err := json.Marshal(&tj) 738 + if err != nil { 739 + buf = []byte("{\"type\": \"" + twirp.Internal + "\", \"msg\": \"There was an error but it could not be serialized into JSON\"}") // fallback 740 + } 741 + 742 + return buf 743 + } 744 + 745 + // errorFromResponse builds a twirp.Error from a non-200 HTTP response. 746 + // If the response has a valid serialized Twirp error, then it's returned. 747 + // If not, the response status code is used to generate a similar twirp 748 + // error. See twirpErrorFromIntermediary for more info on intermediary errors. 749 + func errorFromResponse(resp *http.Response) twirp.Error { 750 + statusCode := resp.StatusCode 751 + statusText := http.StatusText(statusCode) 752 + 753 + if isHTTPRedirect(statusCode) { 754 + // Unexpected redirect: it must be an error from an intermediary. 755 + // Twirp clients don't follow redirects automatically, Twirp only handles 756 + // POST requests, redirects should only happen on GET and HEAD requests. 757 + location := resp.Header.Get("Location") 758 + msg := fmt.Sprintf("unexpected HTTP status code %d %q received, Location=%q", statusCode, statusText, location) 759 + return twirpErrorFromIntermediary(statusCode, msg, location) 760 + } 761 + 762 + respBodyBytes, err := io.ReadAll(resp.Body) 763 + if err != nil { 764 + return wrapInternal(err, "failed to read server error response body") 765 + } 766 + 767 + var tj twerrJSON 768 + dec := json.NewDecoder(bytes.NewReader(respBodyBytes)) 769 + dec.DisallowUnknownFields() 770 + if err := dec.Decode(&tj); err != nil || tj.Code == "" { 771 + // Invalid JSON response; it must be an error from an intermediary. 772 + msg := fmt.Sprintf("Error from intermediary with HTTP status code %d %q", statusCode, statusText) 773 + return twirpErrorFromIntermediary(statusCode, msg, string(respBodyBytes)) 774 + } 775 + 776 + errorCode := twirp.ErrorCode(tj.Code) 777 + if !twirp.IsValidErrorCode(errorCode) { 778 + msg := "invalid type returned from server error response: " + tj.Code 779 + return twirp.InternalError(msg).WithMeta("body", string(respBodyBytes)) 780 + } 781 + 782 + twerr := twirp.NewError(errorCode, tj.Msg) 783 + for k, v := range tj.Meta { 784 + twerr = twerr.WithMeta(k, v) 785 + } 786 + return twerr 787 + } 788 + 789 + // twirpErrorFromIntermediary maps HTTP errors from non-twirp sources to twirp errors. 790 + // The mapping is similar to gRPC: https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md. 791 + // Returned twirp Errors have some additional metadata for inspection. 792 + func twirpErrorFromIntermediary(status int, msg string, bodyOrLocation string) twirp.Error { 793 + var code twirp.ErrorCode 794 + if isHTTPRedirect(status) { // 3xx 795 + code = twirp.Internal 796 + } else { 797 + switch status { 798 + case 400: // Bad Request 799 + code = twirp.Internal 800 + case 401: // Unauthorized 801 + code = twirp.Unauthenticated 802 + case 403: // Forbidden 803 + code = twirp.PermissionDenied 804 + case 404: // Not Found 805 + code = twirp.BadRoute 806 + case 429: // Too Many Requests 807 + code = twirp.ResourceExhausted 808 + case 502, 503, 504: // Bad Gateway, Service Unavailable, Gateway Timeout 809 + code = twirp.Unavailable 810 + default: // All other codes 811 + code = twirp.Unknown 812 + } 813 + } 814 + 815 + twerr := twirp.NewError(code, msg) 816 + twerr = twerr.WithMeta("http_error_from_intermediary", "true") // to easily know if this error was from intermediary 817 + twerr = twerr.WithMeta("status_code", strconv.Itoa(status)) 818 + if isHTTPRedirect(status) { 819 + twerr = twerr.WithMeta("location", bodyOrLocation) 820 + } else { 821 + twerr = twerr.WithMeta("body", bodyOrLocation) 822 + } 823 + return twerr 824 + } 825 + 826 + func isHTTPRedirect(status int) bool { 827 + return status >= 300 && status <= 399 828 + } 829 + 830 + // wrapInternal wraps an error with a prefix as an Internal error. 831 + // The original error cause is accessible by github.com/pkg/errors.Cause. 832 + func wrapInternal(err error, prefix string) twirp.Error { 833 + return twirp.InternalErrorWith(&wrappedError{prefix: prefix, cause: err}) 834 + } 835 + 836 + type wrappedError struct { 837 + prefix string 838 + cause error 839 + } 840 + 841 + func (e *wrappedError) Error() string { return e.prefix + ": " + e.cause.Error() } 842 + func (e *wrappedError) Unwrap() error { return e.cause } // for go1.13 + errors.Is/As 843 + func (e *wrappedError) Cause() error { return e.cause } // for github.com/pkg/errors 844 + 845 + // ensurePanicResponses makes sure that rpc methods causing a panic still result in a Twirp Internal 846 + // error response (status 500), and error hooks are properly called with the panic wrapped as an error. 847 + // The panic is re-raised so it can be handled normally with middleware. 848 + func ensurePanicResponses(ctx context.Context, resp http.ResponseWriter, hooks *twirp.ServerHooks) { 849 + if r := recover(); r != nil { 850 + // Wrap the panic as an error so it can be passed to error hooks. 851 + // The original error is accessible from error hooks, but not visible in the response. 852 + err := errFromPanic(r) 853 + twerr := &internalWithCause{msg: "Internal service panic", cause: err} 854 + // Actually write the error 855 + writeError(ctx, resp, twerr, hooks) 856 + // If possible, flush the error to the wire. 857 + f, ok := resp.(http.Flusher) 858 + if ok { 859 + f.Flush() 860 + } 861 + 862 + panic(r) 863 + } 864 + } 865 + 866 + // errFromPanic returns the typed error if the recovered panic is an error, otherwise formats as error. 867 + func errFromPanic(p interface{}) error { 868 + if err, ok := p.(error); ok { 869 + return err 870 + } 871 + return fmt.Errorf("panic: %v", p) 872 + } 873 + 874 + // internalWithCause is a Twirp Internal error wrapping an original error cause, 875 + // but the original error message is not exposed on Msg(). The original error 876 + // can be checked with go1.13+ errors.Is/As, and also by (github.com/pkg/errors).Unwrap 877 + type internalWithCause struct { 878 + msg string 879 + cause error 880 + } 881 + 882 + func (e *internalWithCause) Unwrap() error { return e.cause } // for go1.13 + errors.Is/As 883 + func (e *internalWithCause) Cause() error { return e.cause } // for github.com/pkg/errors 884 + func (e *internalWithCause) Error() string { return e.msg + ": " + e.cause.Error() } 885 + func (e *internalWithCause) Code() twirp.ErrorCode { return twirp.Internal } 886 + func (e *internalWithCause) Msg() string { return e.msg } 887 + func (e *internalWithCause) Meta(key string) string { return "" } 888 + func (e *internalWithCause) MetaMap() map[string]string { return nil } 889 + func (e *internalWithCause) WithMeta(key string, val string) twirp.Error { return e } 890 + 891 + // malformedRequestError is used when the twirp server cannot unmarshal a request 892 + func malformedRequestError(msg string) twirp.Error { 893 + return twirp.NewError(twirp.Malformed, msg) 894 + } 895 + 896 + // badRouteError is used when the twirp server cannot route a request 897 + func badRouteError(msg string, method, url string) twirp.Error { 898 + err := twirp.NewError(twirp.BadRoute, msg) 899 + err = err.WithMeta("twirp_invalid_route", method+" "+url) 900 + return err 901 + } 902 + 903 + // withoutRedirects makes sure that the POST request can not be redirected. 904 + // The standard library will, by default, redirect requests (including POSTs) if it gets a 302 or 905 + // 303 response, and also 301s in go1.8. It redirects by making a second request, changing the 906 + // method to GET and removing the body. This produces very confusing error messages, so instead we 907 + // set a redirect policy that always errors. This stops Go from executing the redirect. 908 + // 909 + // We have to be a little careful in case the user-provided http.Client has its own CheckRedirect 910 + // policy - if so, we'll run through that policy first. 911 + // 912 + // Because this requires modifying the http.Client, we make a new copy of the client and return it. 913 + func withoutRedirects(in *http.Client) *http.Client { 914 + copy := *in 915 + copy.CheckRedirect = func(req *http.Request, via []*http.Request) error { 916 + if in.CheckRedirect != nil { 917 + // Run the input's redirect if it exists, in case it has side effects, but ignore any error it 918 + // returns, since we want to use ErrUseLastResponse. 919 + err := in.CheckRedirect(req, via) 920 + _ = err // Silly, but this makes sure generated code passes errcheck -blank, which some people use. 921 + } 922 + return http.ErrUseLastResponse 923 + } 924 + return &copy 925 + } 926 + 927 + // doProtobufRequest makes a Protobuf request to the remote Twirp service. 928 + func doProtobufRequest(ctx context.Context, client HTTPClient, hooks *twirp.ClientHooks, url string, in, out proto.Message) (_ context.Context, err error) { 929 + reqBodyBytes, err := proto.Marshal(in) 930 + if err != nil { 931 + return ctx, wrapInternal(err, "failed to marshal proto request") 932 + } 933 + reqBody := bytes.NewBuffer(reqBodyBytes) 934 + if err = ctx.Err(); err != nil { 935 + return ctx, wrapInternal(err, "aborted because context was done") 936 + } 937 + 938 + req, err := newRequest(ctx, url, reqBody, "application/protobuf") 939 + if err != nil { 940 + return ctx, wrapInternal(err, "could not build request") 941 + } 942 + ctx, err = callClientRequestPrepared(ctx, hooks, req) 943 + if err != nil { 944 + return ctx, err 945 + } 946 + 947 + req = req.WithContext(ctx) 948 + resp, err := client.Do(req) 949 + if err != nil { 950 + return ctx, wrapInternal(err, "failed to do request") 951 + } 952 + defer func() { _ = resp.Body.Close() }() 953 + 954 + if err = ctx.Err(); err != nil { 955 + return ctx, wrapInternal(err, "aborted because context was done") 956 + } 957 + 958 + if resp.StatusCode != 200 { 959 + return ctx, errorFromResponse(resp) 960 + } 961 + 962 + respBodyBytes, err := io.ReadAll(resp.Body) 963 + if err != nil { 964 + return ctx, wrapInternal(err, "failed to read response body") 965 + } 966 + if err = ctx.Err(); err != nil { 967 + return ctx, wrapInternal(err, "aborted because context was done") 968 + } 969 + 970 + if err = proto.Unmarshal(respBodyBytes, out); err != nil { 971 + return ctx, wrapInternal(err, "failed to unmarshal proto response") 972 + } 973 + return ctx, nil 974 + } 975 + 976 + // doJSONRequest makes a JSON request to the remote Twirp service. 977 + func doJSONRequest(ctx context.Context, client HTTPClient, hooks *twirp.ClientHooks, url string, in, out proto.Message) (_ context.Context, err error) { 978 + marshaler := &protojson.MarshalOptions{UseProtoNames: true} 979 + reqBytes, err := marshaler.Marshal(in) 980 + if err != nil { 981 + return ctx, wrapInternal(err, "failed to marshal json request") 982 + } 983 + if err = ctx.Err(); err != nil { 984 + return ctx, wrapInternal(err, "aborted because context was done") 985 + } 986 + 987 + req, err := newRequest(ctx, url, bytes.NewReader(reqBytes), "application/json") 988 + if err != nil { 989 + return ctx, wrapInternal(err, "could not build request") 990 + } 991 + ctx, err = callClientRequestPrepared(ctx, hooks, req) 992 + if err != nil { 993 + return ctx, err 994 + } 995 + 996 + req = req.WithContext(ctx) 997 + resp, err := client.Do(req) 998 + if err != nil { 999 + return ctx, wrapInternal(err, "failed to do request") 1000 + } 1001 + 1002 + defer func() { 1003 + cerr := resp.Body.Close() 1004 + if err == nil && cerr != nil { 1005 + err = wrapInternal(cerr, "failed to close response body") 1006 + } 1007 + }() 1008 + 1009 + if err = ctx.Err(); err != nil { 1010 + return ctx, wrapInternal(err, "aborted because context was done") 1011 + } 1012 + 1013 + if resp.StatusCode != 200 { 1014 + return ctx, errorFromResponse(resp) 1015 + } 1016 + 1017 + d := json.NewDecoder(resp.Body) 1018 + rawRespBody := json.RawMessage{} 1019 + if err := d.Decode(&rawRespBody); err != nil { 1020 + return ctx, wrapInternal(err, "failed to unmarshal json response") 1021 + } 1022 + unmarshaler := protojson.UnmarshalOptions{DiscardUnknown: true} 1023 + if err = unmarshaler.Unmarshal(rawRespBody, out); err != nil { 1024 + return ctx, wrapInternal(err, "failed to unmarshal json response") 1025 + } 1026 + if err = ctx.Err(); err != nil { 1027 + return ctx, wrapInternal(err, "aborted because context was done") 1028 + } 1029 + return ctx, nil 1030 + } 1031 + 1032 + // Call twirp.ServerHooks.RequestReceived if the hook is available 1033 + func callRequestReceived(ctx context.Context, h *twirp.ServerHooks) (context.Context, error) { 1034 + if h == nil || h.RequestReceived == nil { 1035 + return ctx, nil 1036 + } 1037 + return h.RequestReceived(ctx) 1038 + } 1039 + 1040 + // Call twirp.ServerHooks.RequestRouted if the hook is available 1041 + func callRequestRouted(ctx context.Context, h *twirp.ServerHooks) (context.Context, error) { 1042 + if h == nil || h.RequestRouted == nil { 1043 + return ctx, nil 1044 + } 1045 + return h.RequestRouted(ctx) 1046 + } 1047 + 1048 + // Call twirp.ServerHooks.ResponsePrepared if the hook is available 1049 + func callResponsePrepared(ctx context.Context, h *twirp.ServerHooks) context.Context { 1050 + if h == nil || h.ResponsePrepared == nil { 1051 + return ctx 1052 + } 1053 + return h.ResponsePrepared(ctx) 1054 + } 1055 + 1056 + // Call twirp.ServerHooks.ResponseSent if the hook is available 1057 + func callResponseSent(ctx context.Context, h *twirp.ServerHooks) { 1058 + if h == nil || h.ResponseSent == nil { 1059 + return 1060 + } 1061 + h.ResponseSent(ctx) 1062 + } 1063 + 1064 + // Call twirp.ServerHooks.Error if the hook is available 1065 + func callError(ctx context.Context, h *twirp.ServerHooks, err twirp.Error) context.Context { 1066 + if h == nil || h.Error == nil { 1067 + return ctx 1068 + } 1069 + return h.Error(ctx, err) 1070 + } 1071 + 1072 + func callClientResponseReceived(ctx context.Context, h *twirp.ClientHooks) { 1073 + if h == nil || h.ResponseReceived == nil { 1074 + return 1075 + } 1076 + h.ResponseReceived(ctx) 1077 + } 1078 + 1079 + func callClientRequestPrepared(ctx context.Context, h *twirp.ClientHooks, req *http.Request) (context.Context, error) { 1080 + if h == nil || h.RequestPrepared == nil { 1081 + return ctx, nil 1082 + } 1083 + return h.RequestPrepared(ctx, req) 1084 + } 1085 + 1086 + func callClientError(ctx context.Context, h *twirp.ClientHooks, err twirp.Error) { 1087 + if h == nil || h.Error == nil { 1088 + return 1089 + } 1090 + h.Error(ctx, err) 1091 + } 1092 + 1093 + var twirpFileDescriptor0 = []byte{ 1094 + // 315 bytes of a gzipped FileDescriptorProto 1095 + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x91, 0x4f, 0x4b, 0xc3, 0x40, 1096 + 0x10, 0xc5, 0x49, 0xd3, 0xa6, 0xed, 0x14, 0x44, 0x56, 0x90, 0x10, 0xa5, 0x86, 0x9e, 0x7a, 0xda, 1097 + 0x40, 0xd5, 0x83, 0x07, 0x11, 0xc4, 0xda, 0x7b, 0xf0, 0xe4, 0x45, 0x36, 0xdd, 0xb1, 0x2e, 0x64, 1098 + 0x77, 0x43, 0x76, 0xfa, 0xc7, 0x0f, 0xed, 0x77, 0x90, 0x6c, 0xac, 0x88, 0x7f, 0xf0, 0x36, 0xf3, 1099 + 0xf2, 0x7b, 0xf3, 0x66, 0xb2, 0x30, 0xd0, 0x8a, 0x57, 0xb5, 0x25, 0xcb, 0x8e, 0xb6, 0x8a, 0x5e, 1100 + 0x94, 0xe1, 0x5b, 0x2c, 0x9c, 0x22, 0xe4, 0x3b, 0xae, 0x55, 0x72, 0xb2, 0xb2, 0x76, 0x55, 0x62, 1101 + 0xe6, 0x91, 0x62, 0xfd, 0x9c, 0xa1, 0xae, 0xe8, 0xb5, 0x75, 0x24, 0x67, 0xdf, 0x3f, 0x92, 0xd2, 1102 + 0xe8, 0x48, 0xe8, 0xaa, 0x05, 0x26, 0x6f, 0x01, 0xf4, 0xe6, 0x1b, 0x34, 0xc4, 0x18, 0x74, 0x8d, 1103 + 0xd0, 0x18, 0x07, 0x69, 0x30, 0x1d, 0xe6, 0xbe, 0x66, 0x87, 0x10, 0xae, 0xeb, 0x32, 0xee, 0x78, 1104 + 0xa9, 0x29, 0xd9, 0x15, 0x80, 0x23, 0x51, 0xd3, 0x93, 0x14, 0x84, 0x71, 0x98, 0x06, 0xd3, 0xd1, 1105 + 0x2c, 0xe1, 0x6d, 0x0a, 0xdf, 0xa7, 0xf0, 0x87, 0x7d, 0x4a, 0x3e, 0xf4, 0xf4, 0x9d, 0x20, 0x64, 1106 + 0x97, 0x30, 0x40, 0x23, 0x5b, 0x63, 0xf7, 0x5f, 0x63, 0x1f, 0x8d, 0xf4, 0xb6, 0x04, 0x06, 0xa5, 1107 + 0x5d, 0x0a, 0x52, 0xd6, 0xc4, 0x3d, 0xbf, 0xc8, 0x67, 0xcf, 0x0e, 0xa0, 0xa3, 0x64, 0x1c, 0xa5, 1108 + 0xc1, 0xb4, 0x97, 0x77, 0x94, 0x64, 0x29, 0x8c, 0x24, 0xba, 0x65, 0xad, 0x2a, 0x8f, 0xf7, 0x3d, 1109 + 0xfe, 0x55, 0x9a, 0xdc, 0xc0, 0xd0, 0x9f, 0x7b, 0x8f, 0x28, 0xd9, 0x0c, 0x22, 0x6c, 0x1a, 0x17, 1110 + 0x07, 0x69, 0xe8, 0xf7, 0xf9, 0xe5, 0x07, 0x73, 0xcf, 0xe7, 0x1f, 0xe4, 0x6c, 0x01, 0x91, 0x17, 1111 + 0x1c, 0xbb, 0x86, 0x70, 0x81, 0xc4, 0x8e, 0x7f, 0x1c, 0x31, 0x6f, 0x1e, 0x20, 0x19, 0xff, 0x3d, 1112 + 0xac, 0x09, 0xbf, 0x1d, 0x3f, 0x9e, 0xee, 0x50, 0x09, 0x67, 0xb9, 0x41, 0xca, 0x36, 0x17, 0x59, 1113 + 0x55, 0x64, 0xb8, 0x23, 0xac, 0x8d, 0x28, 0x33, 0xad, 0x8a, 0xc8, 0xcf, 0x3b, 0x7f, 0x0f, 0x00, 1114 + 0x00, 0xff, 0xff, 0xfd, 0x46, 0x1a, 0xf8, 0xff, 0x01, 0x00, 0x00, 1115 + }
+1 -1
pb/external/mimi/announce/mimi-announce.pb.go
··· 1 1 // Code generated by protoc-gen-go. DO NOT EDIT. 2 2 // versions: 3 3 // protoc-gen-go v1.32.0 4 - // protoc v4.25.3 4 + // protoc v5.26.1 5 5 // source: mimi-announce.proto 6 6 7 7 package announce
+1 -1
pb/external/protofeed/protofeed.pb.go
··· 1 1 // Code generated by protoc-gen-go. DO NOT EDIT. 2 2 // versions: 3 3 // protoc-gen-go v1.32.0 4 - // protoc v4.25.3 4 + // protoc v5.26.1 5 5 // source: protofeed.proto 6 6 7 7 package protofeed
+77
pb/openapi.json
··· 185 185 }, 186 186 "type": "object" 187 187 }, 188 + "within.website.x.mi.Event": { 189 + "description": "Event is a single event that Xe will be attending.", 190 + "properties": { 191 + "description": { 192 + "description": "The description of the event", 193 + "type": "string" 194 + }, 195 + "end_date": { 196 + "description": "The day the event ends", 197 + "format": "date-time", 198 + "type": "string" 199 + }, 200 + "id": { 201 + "description": "The ID of the event", 202 + "format": "int32", 203 + "type": "integer" 204 + }, 205 + "location": { 206 + "description": "The location of the event (human-readable)", 207 + "type": "string" 208 + }, 209 + "name": { 210 + "description": "The name of the event", 211 + "type": "string" 212 + }, 213 + "start_date": { 214 + "description": "The day the event starts", 215 + "format": "date-time", 216 + "type": "string" 217 + }, 218 + "url": { 219 + "description": "The URL for the event", 220 + "type": "string" 221 + } 222 + }, 223 + "type": "object" 224 + }, 225 + "within.website.x.mi.EventFeed": { 226 + "description": "A feed of events, result from mi query.", 227 + "properties": { 228 + "events": { 229 + "description": "The events in the feed", 230 + "items": { 231 + "$ref": "#/components/schemas/within.website.x.mi.Event" 232 + }, 233 + "type": "array" 234 + } 235 + }, 236 + "type": "object" 237 + }, 188 238 "xeiaso.net.BuildInfo": { 189 239 "description": "BuildInfo contains metadata about a build of the site.", 190 240 "properties": { ··· 220 270 }, 221 271 "openapi": "3.0.0", 222 272 "paths": { 273 + "/api/xeiaso.net.Events/Get": { 274 + "post": { 275 + "description": "\nGet fetches the current feed of upcoming events.", 276 + "requestBody": { 277 + "content": { 278 + "application/json": { 279 + "schema": { 280 + "$ref": "#/components/schemas/google.protobuf.Empty" 281 + } 282 + } 283 + } 284 + }, 285 + "responses": { 286 + "200": { 287 + "content": { 288 + "application/json": { 289 + "schema": { 290 + "$ref": "#/components/schemas/within.website.x.mi.EventFeed" 291 + } 292 + } 293 + }, 294 + "description": "Success" 295 + } 296 + }, 297 + "summary": "Get" 298 + } 299 + }, 223 300 "/api/xeiaso.net.Feed/Get": { 224 301 "post": { 225 302 "description": "\nGet fetches the current feed of posts.",
+40 -31
pb/xesite.pb.go
··· 1 1 // Code generated by protoc-gen-go. DO NOT EDIT. 2 2 // versions: 3 3 // protoc-gen-go v1.32.0 4 - // protoc v4.24.4 4 + // protoc v5.26.1 5 5 // source: xesite.proto 6 6 7 7 package pb ··· 13 13 timestamppb "google.golang.org/protobuf/types/known/timestamppb" 14 14 reflect "reflect" 15 15 sync "sync" 16 + mi "xeiaso.net/v4/pb/external/mi" 16 17 protofeed "xeiaso.net/v4/pb/external/protofeed" 17 18 ) 18 19 ··· 116 117 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 117 118 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 118 119 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 119 - 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 120 - 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x66, 0x65, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 121 - 0x74, 0x6f, 0x22, 0xc7, 0x01, 0x0a, 0x09, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 122 - 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 123 - 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x62, 0x75, 0x69, 0x6c, 124 - 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 125 - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 126 - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x54, 127 - 0x69, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 128 - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x6f, 0x56, 0x65, 0x72, 0x73, 0x69, 129 - 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x6e, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 130 - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x6e, 0x6f, 0x56, 0x65, 131 - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x78, 0x65, 0x73, 0x69, 0x74, 0x65, 0x5f, 132 - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x78, 133 - 0x65, 0x73, 0x69, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x32, 0x41, 0x0a, 0x04, 134 - 0x4d, 0x65, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 135 - 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 136 - 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x78, 0x65, 0x69, 0x61, 0x73, 137 - 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x32, 138 - 0x36, 0x0a, 0x04, 0x46, 0x65, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x16, 139 - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 140 - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x66, 0x65, 141 - 0x65, 0x64, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x42, 0x12, 0x5a, 0x10, 0x78, 0x65, 0x69, 0x61, 0x73, 142 - 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x76, 0x34, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 143 - 0x74, 0x6f, 0x33, 120 + 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 121 + 0x61, 0x6c, 0x2f, 0x6d, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x18, 0x65, 0x78, 0x74, 122 + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x66, 0x65, 0x65, 0x64, 0x2e, 123 + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc7, 0x01, 0x0a, 0x09, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 124 + 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 125 + 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x62, 126 + 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 127 + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 128 + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x62, 0x75, 0x69, 129 + 0x6c, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x6f, 0x5f, 0x76, 0x65, 0x72, 130 + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x6f, 0x56, 0x65, 131 + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x6e, 0x6f, 0x5f, 0x76, 0x65, 132 + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x6e, 133 + 0x6f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x78, 0x65, 0x73, 0x69, 134 + 0x74, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 135 + 0x52, 0x0d, 0x78, 0x65, 0x73, 0x69, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x32, 136 + 0x41, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 137 + 0x61, 0x74, 0x61, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 138 + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x15, 0x2e, 0x78, 0x65, 139 + 0x69, 0x61, 0x73, 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x6e, 140 + 0x66, 0x6f, 0x32, 0x36, 0x0a, 0x04, 0x46, 0x65, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x03, 0x47, 0x65, 141 + 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 142 + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 143 + 0x6f, 0x66, 0x65, 0x65, 0x64, 0x2e, 0x46, 0x65, 0x65, 0x64, 0x32, 0x47, 0x0a, 0x06, 0x45, 0x76, 144 + 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3d, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 145 + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 146 + 0x70, 0x74, 0x79, 0x1a, 0x1e, 0x2e, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x2e, 0x77, 0x65, 0x62, 147 + 0x73, 0x69, 0x74, 0x65, 0x2e, 0x78, 0x2e, 0x6d, 0x69, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x46, 148 + 0x65, 0x65, 0x64, 0x42, 0x12, 0x5a, 0x10, 0x78, 0x65, 0x69, 0x61, 0x73, 0x6f, 0x2e, 0x6e, 0x65, 149 + 0x74, 0x2f, 0x76, 0x34, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 144 150 } 145 151 146 152 var ( ··· 161 167 (*timestamppb.Timestamp)(nil), // 1: google.protobuf.Timestamp 162 168 (*emptypb.Empty)(nil), // 2: google.protobuf.Empty 163 169 (*protofeed.Feed)(nil), // 3: protofeed.Feed 170 + (*mi.EventFeed)(nil), // 4: within.website.x.mi.EventFeed 164 171 } 165 172 var file_xesite_proto_depIdxs = []int32{ 166 173 1, // 0: xeiaso.net.BuildInfo.build_time:type_name -> google.protobuf.Timestamp 167 174 2, // 1: xeiaso.net.Meta.Metadata:input_type -> google.protobuf.Empty 168 175 2, // 2: xeiaso.net.Feed.Get:input_type -> google.protobuf.Empty 169 - 0, // 3: xeiaso.net.Meta.Metadata:output_type -> xeiaso.net.BuildInfo 170 - 3, // 4: xeiaso.net.Feed.Get:output_type -> protofeed.Feed 171 - 3, // [3:5] is the sub-list for method output_type 172 - 1, // [1:3] is the sub-list for method input_type 176 + 2, // 3: xeiaso.net.Events.Get:input_type -> google.protobuf.Empty 177 + 0, // 4: xeiaso.net.Meta.Metadata:output_type -> xeiaso.net.BuildInfo 178 + 3, // 5: xeiaso.net.Feed.Get:output_type -> protofeed.Feed 179 + 4, // 6: xeiaso.net.Events.Get:output_type -> within.website.x.mi.EventFeed 180 + 4, // [4:7] is the sub-list for method output_type 181 + 1, // [1:4] is the sub-list for method input_type 173 182 1, // [1:1] is the sub-list for extension type_name 174 183 1, // [1:1] is the sub-list for extension extendee 175 184 0, // [0:1] is the sub-list for field type_name ··· 202 211 NumEnums: 0, 203 212 NumMessages: 1, 204 213 NumExtensions: 0, 205 - NumServices: 2, 214 + NumServices: 3, 206 215 }, 207 216 GoTypes: file_xesite_proto_goTypes, 208 217 DependencyIndexes: file_xesite_proto_depIdxs,
+7
pb/xesite.proto
··· 5 5 import "google/protobuf/empty.proto"; 6 6 import "google/protobuf/timestamp.proto"; 7 7 8 + import "external/mi.proto"; // unused in this file 8 9 import "external/protofeed.proto"; 9 10 10 11 // Meta lets users fetch site metadata. ··· 32 33 service Feed { 33 34 // Get fetches the current feed of posts. 34 35 rpc Get(google.protobuf.Empty) returns (protofeed.Feed); 36 + } 37 + 38 + // Events lets users fetch the current feed of events that Xe will be attending. 39 + service Events { 40 + // Get fetches the current feed of upcoming events. 41 + rpc Get(google.protobuf.Empty) returns (within.website.x.mi.EventFeed); 35 42 }
+519 -20
pb/xesite.twirp.go
··· 18 18 19 19 import google_protobuf "google.golang.org/protobuf/types/known/emptypb" 20 20 import protofeed "xeiaso.net/v4/pb/external/protofeed" 21 + import within_website_x_mi "xeiaso.net/v4/pb/external/mi" 21 22 22 23 import bytes "bytes" 23 24 import errors "errors" ··· 1023 1024 return baseServicePath(s.pathPrefix, "xeiaso.net", "Feed") 1024 1025 } 1025 1026 1027 + // ================ 1028 + // Events Interface 1029 + // ================ 1030 + 1031 + // Events lets users fetch the current feed of events that Xe will be attending. 1032 + type Events interface { 1033 + // Get fetches the current feed of upcoming events. 1034 + Get(context.Context, *google_protobuf.Empty) (*within_website_x_mi.EventFeed, error) 1035 + } 1036 + 1037 + // ====================== 1038 + // Events Protobuf Client 1039 + // ====================== 1040 + 1041 + type eventsProtobufClient struct { 1042 + client HTTPClient 1043 + urls [1]string 1044 + interceptor twirp.Interceptor 1045 + opts twirp.ClientOptions 1046 + } 1047 + 1048 + // NewEventsProtobufClient creates a Protobuf client that implements the Events interface. 1049 + // It communicates using Protobuf and can be configured with a custom HTTPClient. 1050 + func NewEventsProtobufClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) Events { 1051 + if c, ok := client.(*http.Client); ok { 1052 + client = withoutRedirects(c) 1053 + } 1054 + 1055 + clientOpts := twirp.ClientOptions{} 1056 + for _, o := range opts { 1057 + o(&clientOpts) 1058 + } 1059 + 1060 + // Using ReadOpt allows backwards and forwards compatibility with new options in the future 1061 + literalURLs := false 1062 + _ = clientOpts.ReadOpt("literalURLs", &literalURLs) 1063 + var pathPrefix string 1064 + if ok := clientOpts.ReadOpt("pathPrefix", &pathPrefix); !ok { 1065 + pathPrefix = "/twirp" // default prefix 1066 + } 1067 + 1068 + // Build method URLs: <baseURL>[<prefix>]/<package>.<Service>/<Method> 1069 + serviceURL := sanitizeBaseURL(baseURL) 1070 + serviceURL += baseServicePath(pathPrefix, "xeiaso.net", "Events") 1071 + urls := [1]string{ 1072 + serviceURL + "Get", 1073 + } 1074 + 1075 + return &eventsProtobufClient{ 1076 + client: client, 1077 + urls: urls, 1078 + interceptor: twirp.ChainInterceptors(clientOpts.Interceptors...), 1079 + opts: clientOpts, 1080 + } 1081 + } 1082 + 1083 + func (c *eventsProtobufClient) Get(ctx context.Context, in *google_protobuf.Empty) (*within_website_x_mi.EventFeed, error) { 1084 + ctx = ctxsetters.WithPackageName(ctx, "xeiaso.net") 1085 + ctx = ctxsetters.WithServiceName(ctx, "Events") 1086 + ctx = ctxsetters.WithMethodName(ctx, "Get") 1087 + caller := c.callGet 1088 + if c.interceptor != nil { 1089 + caller = func(ctx context.Context, req *google_protobuf.Empty) (*within_website_x_mi.EventFeed, error) { 1090 + resp, err := c.interceptor( 1091 + func(ctx context.Context, req interface{}) (interface{}, error) { 1092 + typedReq, ok := req.(*google_protobuf.Empty) 1093 + if !ok { 1094 + return nil, twirp.InternalError("failed type assertion req.(*google_protobuf.Empty) when calling interceptor") 1095 + } 1096 + return c.callGet(ctx, typedReq) 1097 + }, 1098 + )(ctx, req) 1099 + if resp != nil { 1100 + typedResp, ok := resp.(*within_website_x_mi.EventFeed) 1101 + if !ok { 1102 + return nil, twirp.InternalError("failed type assertion resp.(*within_website_x_mi.EventFeed) when calling interceptor") 1103 + } 1104 + return typedResp, err 1105 + } 1106 + return nil, err 1107 + } 1108 + } 1109 + return caller(ctx, in) 1110 + } 1111 + 1112 + func (c *eventsProtobufClient) callGet(ctx context.Context, in *google_protobuf.Empty) (*within_website_x_mi.EventFeed, error) { 1113 + out := new(within_website_x_mi.EventFeed) 1114 + ctx, err := doProtobufRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) 1115 + if err != nil { 1116 + twerr, ok := err.(twirp.Error) 1117 + if !ok { 1118 + twerr = twirp.InternalErrorWith(err) 1119 + } 1120 + callClientError(ctx, c.opts.Hooks, twerr) 1121 + return nil, err 1122 + } 1123 + 1124 + callClientResponseReceived(ctx, c.opts.Hooks) 1125 + 1126 + return out, nil 1127 + } 1128 + 1129 + // ================== 1130 + // Events JSON Client 1131 + // ================== 1132 + 1133 + type eventsJSONClient struct { 1134 + client HTTPClient 1135 + urls [1]string 1136 + interceptor twirp.Interceptor 1137 + opts twirp.ClientOptions 1138 + } 1139 + 1140 + // NewEventsJSONClient creates a JSON client that implements the Events interface. 1141 + // It communicates using JSON and can be configured with a custom HTTPClient. 1142 + func NewEventsJSONClient(baseURL string, client HTTPClient, opts ...twirp.ClientOption) Events { 1143 + if c, ok := client.(*http.Client); ok { 1144 + client = withoutRedirects(c) 1145 + } 1146 + 1147 + clientOpts := twirp.ClientOptions{} 1148 + for _, o := range opts { 1149 + o(&clientOpts) 1150 + } 1151 + 1152 + // Using ReadOpt allows backwards and forwards compatibility with new options in the future 1153 + literalURLs := false 1154 + _ = clientOpts.ReadOpt("literalURLs", &literalURLs) 1155 + var pathPrefix string 1156 + if ok := clientOpts.ReadOpt("pathPrefix", &pathPrefix); !ok { 1157 + pathPrefix = "/twirp" // default prefix 1158 + } 1159 + 1160 + // Build method URLs: <baseURL>[<prefix>]/<package>.<Service>/<Method> 1161 + serviceURL := sanitizeBaseURL(baseURL) 1162 + serviceURL += baseServicePath(pathPrefix, "xeiaso.net", "Events") 1163 + urls := [1]string{ 1164 + serviceURL + "Get", 1165 + } 1166 + 1167 + return &eventsJSONClient{ 1168 + client: client, 1169 + urls: urls, 1170 + interceptor: twirp.ChainInterceptors(clientOpts.Interceptors...), 1171 + opts: clientOpts, 1172 + } 1173 + } 1174 + 1175 + func (c *eventsJSONClient) Get(ctx context.Context, in *google_protobuf.Empty) (*within_website_x_mi.EventFeed, error) { 1176 + ctx = ctxsetters.WithPackageName(ctx, "xeiaso.net") 1177 + ctx = ctxsetters.WithServiceName(ctx, "Events") 1178 + ctx = ctxsetters.WithMethodName(ctx, "Get") 1179 + caller := c.callGet 1180 + if c.interceptor != nil { 1181 + caller = func(ctx context.Context, req *google_protobuf.Empty) (*within_website_x_mi.EventFeed, error) { 1182 + resp, err := c.interceptor( 1183 + func(ctx context.Context, req interface{}) (interface{}, error) { 1184 + typedReq, ok := req.(*google_protobuf.Empty) 1185 + if !ok { 1186 + return nil, twirp.InternalError("failed type assertion req.(*google_protobuf.Empty) when calling interceptor") 1187 + } 1188 + return c.callGet(ctx, typedReq) 1189 + }, 1190 + )(ctx, req) 1191 + if resp != nil { 1192 + typedResp, ok := resp.(*within_website_x_mi.EventFeed) 1193 + if !ok { 1194 + return nil, twirp.InternalError("failed type assertion resp.(*within_website_x_mi.EventFeed) when calling interceptor") 1195 + } 1196 + return typedResp, err 1197 + } 1198 + return nil, err 1199 + } 1200 + } 1201 + return caller(ctx, in) 1202 + } 1203 + 1204 + func (c *eventsJSONClient) callGet(ctx context.Context, in *google_protobuf.Empty) (*within_website_x_mi.EventFeed, error) { 1205 + out := new(within_website_x_mi.EventFeed) 1206 + ctx, err := doJSONRequest(ctx, c.client, c.opts.Hooks, c.urls[0], in, out) 1207 + if err != nil { 1208 + twerr, ok := err.(twirp.Error) 1209 + if !ok { 1210 + twerr = twirp.InternalErrorWith(err) 1211 + } 1212 + callClientError(ctx, c.opts.Hooks, twerr) 1213 + return nil, err 1214 + } 1215 + 1216 + callClientResponseReceived(ctx, c.opts.Hooks) 1217 + 1218 + return out, nil 1219 + } 1220 + 1221 + // ===================== 1222 + // Events Server Handler 1223 + // ===================== 1224 + 1225 + type eventsServer struct { 1226 + Events 1227 + interceptor twirp.Interceptor 1228 + hooks *twirp.ServerHooks 1229 + pathPrefix string // prefix for routing 1230 + jsonSkipDefaults bool // do not include unpopulated fields (default values) in the response 1231 + jsonCamelCase bool // JSON fields are serialized as lowerCamelCase rather than keeping the original proto names 1232 + } 1233 + 1234 + // NewEventsServer builds a TwirpServer that can be used as an http.Handler to handle 1235 + // HTTP requests that are routed to the right method in the provided svc implementation. 1236 + // The opts are twirp.ServerOption modifiers, for example twirp.WithServerHooks(hooks). 1237 + func NewEventsServer(svc Events, opts ...interface{}) TwirpServer { 1238 + serverOpts := newServerOpts(opts) 1239 + 1240 + // Using ReadOpt allows backwards and forwards compatibility with new options in the future 1241 + jsonSkipDefaults := false 1242 + _ = serverOpts.ReadOpt("jsonSkipDefaults", &jsonSkipDefaults) 1243 + jsonCamelCase := false 1244 + _ = serverOpts.ReadOpt("jsonCamelCase", &jsonCamelCase) 1245 + var pathPrefix string 1246 + if ok := serverOpts.ReadOpt("pathPrefix", &pathPrefix); !ok { 1247 + pathPrefix = "/twirp" // default prefix 1248 + } 1249 + 1250 + return &eventsServer{ 1251 + Events: svc, 1252 + hooks: serverOpts.Hooks, 1253 + interceptor: twirp.ChainInterceptors(serverOpts.Interceptors...), 1254 + pathPrefix: pathPrefix, 1255 + jsonSkipDefaults: jsonSkipDefaults, 1256 + jsonCamelCase: jsonCamelCase, 1257 + } 1258 + } 1259 + 1260 + // writeError writes an HTTP response with a valid Twirp error format, and triggers hooks. 1261 + // If err is not a twirp.Error, it will get wrapped with twirp.InternalErrorWith(err) 1262 + func (s *eventsServer) writeError(ctx context.Context, resp http.ResponseWriter, err error) { 1263 + writeError(ctx, resp, err, s.hooks) 1264 + } 1265 + 1266 + // handleRequestBodyError is used to handle error when the twirp server cannot read request 1267 + func (s *eventsServer) handleRequestBodyError(ctx context.Context, resp http.ResponseWriter, msg string, err error) { 1268 + if context.Canceled == ctx.Err() { 1269 + s.writeError(ctx, resp, twirp.NewError(twirp.Canceled, "failed to read request: context canceled")) 1270 + return 1271 + } 1272 + if context.DeadlineExceeded == ctx.Err() { 1273 + s.writeError(ctx, resp, twirp.NewError(twirp.DeadlineExceeded, "failed to read request: deadline exceeded")) 1274 + return 1275 + } 1276 + s.writeError(ctx, resp, twirp.WrapError(malformedRequestError(msg), err)) 1277 + } 1278 + 1279 + // EventsPathPrefix is a convenience constant that may identify URL paths. 1280 + // Should be used with caution, it only matches routes generated by Twirp Go clients, 1281 + // with the default "/twirp" prefix and default CamelCase service and method names. 1282 + // More info: https://twitchtv.github.io/twirp/docs/routing.html 1283 + const EventsPathPrefix = "/twirp/xeiaso.net.Events/" 1284 + 1285 + func (s *eventsServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) { 1286 + ctx := req.Context() 1287 + ctx = ctxsetters.WithPackageName(ctx, "xeiaso.net") 1288 + ctx = ctxsetters.WithServiceName(ctx, "Events") 1289 + ctx = ctxsetters.WithResponseWriter(ctx, resp) 1290 + 1291 + var err error 1292 + ctx, err = callRequestReceived(ctx, s.hooks) 1293 + if err != nil { 1294 + s.writeError(ctx, resp, err) 1295 + return 1296 + } 1297 + 1298 + if req.Method != "POST" { 1299 + msg := fmt.Sprintf("unsupported method %q (only POST is allowed)", req.Method) 1300 + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) 1301 + return 1302 + } 1303 + 1304 + // Verify path format: [<prefix>]/<package>.<Service>/<Method> 1305 + prefix, pkgService, method := parseTwirpPath(req.URL.Path) 1306 + if pkgService != "xeiaso.net.Events" { 1307 + msg := fmt.Sprintf("no handler for path %q", req.URL.Path) 1308 + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) 1309 + return 1310 + } 1311 + if prefix != s.pathPrefix { 1312 + msg := fmt.Sprintf("invalid path prefix %q, expected %q, on path %q", prefix, s.pathPrefix, req.URL.Path) 1313 + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) 1314 + return 1315 + } 1316 + 1317 + switch method { 1318 + case "Get": 1319 + s.serveGet(ctx, resp, req) 1320 + return 1321 + default: 1322 + msg := fmt.Sprintf("no handler for path %q", req.URL.Path) 1323 + s.writeError(ctx, resp, badRouteError(msg, req.Method, req.URL.Path)) 1324 + return 1325 + } 1326 + } 1327 + 1328 + func (s *eventsServer) serveGet(ctx context.Context, resp http.ResponseWriter, req *http.Request) { 1329 + header := req.Header.Get("Content-Type") 1330 + i := strings.Index(header, ";") 1331 + if i == -1 { 1332 + i = len(header) 1333 + } 1334 + switch strings.TrimSpace(strings.ToLower(header[:i])) { 1335 + case "application/json": 1336 + s.serveGetJSON(ctx, resp, req) 1337 + case "application/protobuf": 1338 + s.serveGetProtobuf(ctx, resp, req) 1339 + default: 1340 + msg := fmt.Sprintf("unexpected Content-Type: %q", req.Header.Get("Content-Type")) 1341 + twerr := badRouteError(msg, req.Method, req.URL.Path) 1342 + s.writeError(ctx, resp, twerr) 1343 + } 1344 + } 1345 + 1346 + func (s *eventsServer) serveGetJSON(ctx context.Context, resp http.ResponseWriter, req *http.Request) { 1347 + var err error 1348 + ctx = ctxsetters.WithMethodName(ctx, "Get") 1349 + ctx, err = callRequestRouted(ctx, s.hooks) 1350 + if err != nil { 1351 + s.writeError(ctx, resp, err) 1352 + return 1353 + } 1354 + 1355 + d := json.NewDecoder(req.Body) 1356 + rawReqBody := json.RawMessage{} 1357 + if err := d.Decode(&rawReqBody); err != nil { 1358 + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) 1359 + return 1360 + } 1361 + reqContent := new(google_protobuf.Empty) 1362 + unmarshaler := protojson.UnmarshalOptions{DiscardUnknown: true} 1363 + if err = unmarshaler.Unmarshal(rawReqBody, reqContent); err != nil { 1364 + s.handleRequestBodyError(ctx, resp, "the json request could not be decoded", err) 1365 + return 1366 + } 1367 + 1368 + handler := s.Events.Get 1369 + if s.interceptor != nil { 1370 + handler = func(ctx context.Context, req *google_protobuf.Empty) (*within_website_x_mi.EventFeed, error) { 1371 + resp, err := s.interceptor( 1372 + func(ctx context.Context, req interface{}) (interface{}, error) { 1373 + typedReq, ok := req.(*google_protobuf.Empty) 1374 + if !ok { 1375 + return nil, twirp.InternalError("failed type assertion req.(*google_protobuf.Empty) when calling interceptor") 1376 + } 1377 + return s.Events.Get(ctx, typedReq) 1378 + }, 1379 + )(ctx, req) 1380 + if resp != nil { 1381 + typedResp, ok := resp.(*within_website_x_mi.EventFeed) 1382 + if !ok { 1383 + return nil, twirp.InternalError("failed type assertion resp.(*within_website_x_mi.EventFeed) when calling interceptor") 1384 + } 1385 + return typedResp, err 1386 + } 1387 + return nil, err 1388 + } 1389 + } 1390 + 1391 + // Call service method 1392 + var respContent *within_website_x_mi.EventFeed 1393 + func() { 1394 + defer ensurePanicResponses(ctx, resp, s.hooks) 1395 + respContent, err = handler(ctx, reqContent) 1396 + }() 1397 + 1398 + if err != nil { 1399 + s.writeError(ctx, resp, err) 1400 + return 1401 + } 1402 + if respContent == nil { 1403 + s.writeError(ctx, resp, twirp.InternalError("received a nil *within_website_x_mi.EventFeed and nil error while calling Get. nil responses are not supported")) 1404 + return 1405 + } 1406 + 1407 + ctx = callResponsePrepared(ctx, s.hooks) 1408 + 1409 + marshaler := &protojson.MarshalOptions{UseProtoNames: !s.jsonCamelCase, EmitUnpopulated: !s.jsonSkipDefaults} 1410 + respBytes, err := marshaler.Marshal(respContent) 1411 + if err != nil { 1412 + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal json response")) 1413 + return 1414 + } 1415 + 1416 + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) 1417 + resp.Header().Set("Content-Type", "application/json") 1418 + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) 1419 + resp.WriteHeader(http.StatusOK) 1420 + 1421 + if n, err := resp.Write(respBytes); err != nil { 1422 + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) 1423 + twerr := twirp.NewError(twirp.Unknown, msg) 1424 + ctx = callError(ctx, s.hooks, twerr) 1425 + } 1426 + callResponseSent(ctx, s.hooks) 1427 + } 1428 + 1429 + func (s *eventsServer) serveGetProtobuf(ctx context.Context, resp http.ResponseWriter, req *http.Request) { 1430 + var err error 1431 + ctx = ctxsetters.WithMethodName(ctx, "Get") 1432 + ctx, err = callRequestRouted(ctx, s.hooks) 1433 + if err != nil { 1434 + s.writeError(ctx, resp, err) 1435 + return 1436 + } 1437 + 1438 + buf, err := io.ReadAll(req.Body) 1439 + if err != nil { 1440 + s.handleRequestBodyError(ctx, resp, "failed to read request body", err) 1441 + return 1442 + } 1443 + reqContent := new(google_protobuf.Empty) 1444 + if err = proto.Unmarshal(buf, reqContent); err != nil { 1445 + s.writeError(ctx, resp, malformedRequestError("the protobuf request could not be decoded")) 1446 + return 1447 + } 1448 + 1449 + handler := s.Events.Get 1450 + if s.interceptor != nil { 1451 + handler = func(ctx context.Context, req *google_protobuf.Empty) (*within_website_x_mi.EventFeed, error) { 1452 + resp, err := s.interceptor( 1453 + func(ctx context.Context, req interface{}) (interface{}, error) { 1454 + typedReq, ok := req.(*google_protobuf.Empty) 1455 + if !ok { 1456 + return nil, twirp.InternalError("failed type assertion req.(*google_protobuf.Empty) when calling interceptor") 1457 + } 1458 + return s.Events.Get(ctx, typedReq) 1459 + }, 1460 + )(ctx, req) 1461 + if resp != nil { 1462 + typedResp, ok := resp.(*within_website_x_mi.EventFeed) 1463 + if !ok { 1464 + return nil, twirp.InternalError("failed type assertion resp.(*within_website_x_mi.EventFeed) when calling interceptor") 1465 + } 1466 + return typedResp, err 1467 + } 1468 + return nil, err 1469 + } 1470 + } 1471 + 1472 + // Call service method 1473 + var respContent *within_website_x_mi.EventFeed 1474 + func() { 1475 + defer ensurePanicResponses(ctx, resp, s.hooks) 1476 + respContent, err = handler(ctx, reqContent) 1477 + }() 1478 + 1479 + if err != nil { 1480 + s.writeError(ctx, resp, err) 1481 + return 1482 + } 1483 + if respContent == nil { 1484 + s.writeError(ctx, resp, twirp.InternalError("received a nil *within_website_x_mi.EventFeed and nil error while calling Get. nil responses are not supported")) 1485 + return 1486 + } 1487 + 1488 + ctx = callResponsePrepared(ctx, s.hooks) 1489 + 1490 + respBytes, err := proto.Marshal(respContent) 1491 + if err != nil { 1492 + s.writeError(ctx, resp, wrapInternal(err, "failed to marshal proto response")) 1493 + return 1494 + } 1495 + 1496 + ctx = ctxsetters.WithStatusCode(ctx, http.StatusOK) 1497 + resp.Header().Set("Content-Type", "application/protobuf") 1498 + resp.Header().Set("Content-Length", strconv.Itoa(len(respBytes))) 1499 + resp.WriteHeader(http.StatusOK) 1500 + if n, err := resp.Write(respBytes); err != nil { 1501 + msg := fmt.Sprintf("failed to write response, %d of %d bytes written: %s", n, len(respBytes), err.Error()) 1502 + twerr := twirp.NewError(twirp.Unknown, msg) 1503 + ctx = callError(ctx, s.hooks, twerr) 1504 + } 1505 + callResponseSent(ctx, s.hooks) 1506 + } 1507 + 1508 + func (s *eventsServer) ServiceDescriptor() ([]byte, int) { 1509 + return twirpFileDescriptor0, 2 1510 + } 1511 + 1512 + func (s *eventsServer) ProtocGenTwirpVersion() string { 1513 + return "v8.1.3" 1514 + } 1515 + 1516 + // PathPrefix returns the base service path, in the form: "/<prefix>/<package>.<Service>/" 1517 + // that is everything in a Twirp route except for the <Method>. This can be used for routing, 1518 + // for example to identify the requests that are targeted to this service in a mux. 1519 + func (s *eventsServer) PathPrefix() string { 1520 + return baseServicePath(s.pathPrefix, "xeiaso.net", "Events") 1521 + } 1522 + 1026 1523 // ===== 1027 1524 // Utils 1028 1525 // ===== ··· 1589 2086 } 1590 2087 1591 2088 var twirpFileDescriptor0 = []byte{ 1592 - // 291 bytes of a gzipped FileDescriptorProto 1593 - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0xd0, 0x4d, 0x4b, 0xf3, 0x40, 1594 - 0x10, 0x07, 0x70, 0xf2, 0x34, 0x4f, 0x31, 0xd3, 0xfa, 0xc2, 0x82, 0x25, 0x44, 0xc4, 0x2a, 0x08, 1595 - 0x3d, 0x6d, 0x20, 0x8a, 0xd0, 0xa3, 0x05, 0x15, 0x0f, 0x5e, 0x8a, 0x78, 0xf0, 0x52, 0x36, 0x66, 1596 - 0x12, 0x16, 0x92, 0x6c, 0x48, 0xa6, 0x25, 0x7e, 0x42, 0xbf, 0x96, 0xec, 0x6e, 0xd2, 0x80, 0xe2, 1597 - 0x29, 0xcc, 0xcc, 0x2f, 0x33, 0xc9, 0x1f, 0xa6, 0x2d, 0x36, 0x92, 0x90, 0x57, 0xb5, 0x22, 0xc5, 1598 - 0xa0, 0x45, 0x29, 0x1a, 0xc5, 0x4b, 0xa4, 0xe0, 0x2c, 0x53, 0x2a, 0xcb, 0x31, 0x34, 0x93, 0x78, 1599 - 0x9b, 0x86, 0x58, 0x54, 0xf4, 0x69, 0x61, 0x70, 0xf1, 0x73, 0x48, 0xb2, 0xc0, 0x86, 0x44, 0x51, 1600 - 0x75, 0xc0, 0xc7, 0x96, 0xb0, 0x2e, 0x45, 0x6e, 0x49, 0x8a, 0x98, 0xd8, 0xc9, 0xd5, 0x97, 0x03, 1601 - 0xde, 0x6a, 0x2b, 0xf3, 0xe4, 0xb9, 0x4c, 0x15, 0x9b, 0xc1, 0xf8, 0x43, 0x15, 0x85, 0x24, 0xdf, 1602 - 0x99, 0x3b, 0x0b, 0x6f, 0xdd, 0x55, 0x6c, 0x09, 0x10, 0x6b, 0xb4, 0xd1, 0x8b, 0xfd, 0x7f, 0x73, 1603 - 0x67, 0x31, 0x89, 0x02, 0x6e, 0xaf, 0xf2, 0xfe, 0x2a, 0x7f, 0xed, 0xaf, 0xae, 0x3d, 0xa3, 0x75, 1604 - 0xcd, 0xce, 0x01, 0x32, 0xb5, 0xd9, 0x61, 0xdd, 0x48, 0x55, 0xfa, 0x23, 0xb3, 0xd6, 0xcb, 0xd4, 1605 - 0x9b, 0x6d, 0xb0, 0x4b, 0x98, 0x26, 0x58, 0x0e, 0xc0, 0x35, 0x60, 0xa2, 0x7b, 0x3d, 0xb9, 0x86, 1606 - 0x23, 0x1b, 0xcb, 0x1e, 0xfd, 0x37, 0xe8, 0xd0, 0x76, 0x3b, 0x16, 0xdd, 0x83, 0xfb, 0x82, 0x24, 1607 - 0xd8, 0x12, 0x0e, 0xf4, 0x33, 0x11, 0x24, 0xd8, 0xec, 0xd7, 0x37, 0x3e, 0xe8, 0xd8, 0x82, 0x53, 1608 - 0x3e, 0x44, 0xcb, 0xf7, 0xbf, 0x1f, 0xdd, 0x81, 0xfb, 0x88, 0x98, 0x30, 0x0e, 0xa3, 0x27, 0xa4, 1609 - 0x3f, 0xdf, 0x3e, 0xe6, 0x43, 0x8a, 0xda, 0xaf, 0xd8, 0xfb, 0xc9, 0xb0, 0x2f, 0xdc, 0xdd, 0x86, 1610 - 0x55, 0x1c, 0x8f, 0x8d, 0xb9, 0xf9, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x20, 0xf7, 0x0a, 0x20, 0xd3, 1611 - 0x01, 0x00, 0x00, 2089 + // 329 bytes of a gzipped FileDescriptorProto 2090 + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0x4f, 0x4b, 0xc3, 0x40, 2091 + 0x10, 0xc5, 0x89, 0xad, 0xc5, 0x4c, 0xeb, 0xbf, 0x05, 0x4b, 0x88, 0xa8, 0x55, 0x10, 0x7a, 0xda, 2092 + 0x40, 0x14, 0xa1, 0x07, 0x0f, 0x16, 0x6a, 0xf1, 0xe0, 0xa5, 0x88, 0x07, 0x2f, 0x25, 0x31, 0xd3, 2093 + 0xb8, 0xd0, 0xdd, 0x0d, 0xcd, 0xb4, 0x8d, 0x9f, 0xd0, 0xaf, 0x25, 0xbb, 0x49, 0x1b, 0x50, 0xf4, 2094 + 0xb4, 0xcc, 0x9b, 0xdf, 0xcc, 0xbe, 0x7d, 0x0b, 0x9d, 0x02, 0x73, 0x41, 0xc8, 0xb3, 0x85, 0x26, 2095 + 0xcd, 0xa0, 0x40, 0x11, 0xe5, 0x9a, 0x2b, 0x24, 0xff, 0x34, 0xd5, 0x3a, 0x9d, 0x63, 0x60, 0x3b, 2096 + 0xf1, 0x72, 0x16, 0xa0, 0xcc, 0xe8, 0xb3, 0x04, 0xfd, 0x8b, 0x9f, 0x4d, 0x12, 0x12, 0x73, 0x8a, 2097 + 0x64, 0x56, 0x01, 0xc7, 0x58, 0x10, 0x2e, 0x54, 0x34, 0x0f, 0xa4, 0xa8, 0x24, 0x6f, 0x2b, 0xd9, 2098 + 0x7a, 0x86, 0x98, 0x94, 0x9d, 0xab, 0x2f, 0x07, 0xdc, 0xe1, 0x52, 0xcc, 0x93, 0x27, 0x35, 0xd3, 2099 + 0xac, 0x0b, 0xad, 0x77, 0x2d, 0xa5, 0x20, 0xcf, 0xe9, 0x39, 0x7d, 0x77, 0x52, 0x55, 0x6c, 0x00, 2100 + 0x10, 0x1b, 0x68, 0x6a, 0xee, 0xf2, 0x76, 0x7a, 0x4e, 0xbf, 0x1d, 0xfa, 0xbc, 0x34, 0xc2, 0x37, 2101 + 0x46, 0xf8, 0xcb, 0xc6, 0xc8, 0xc4, 0xb5, 0xb4, 0xa9, 0xd9, 0x19, 0x40, 0xaa, 0xa7, 0x2b, 0x5c, 2102 + 0xe4, 0x42, 0x2b, 0xaf, 0x61, 0xd7, 0xba, 0xa9, 0x7e, 0x2d, 0x05, 0x76, 0x09, 0x9d, 0x04, 0x55, 2103 + 0x0d, 0x34, 0x2d, 0xd0, 0x36, 0xda, 0x06, 0xb9, 0x86, 0x83, 0x32, 0xa9, 0x2d, 0xb4, 0x6b, 0xa1, 2104 + 0xfd, 0x52, 0xad, 0xb0, 0xf0, 0x01, 0x9a, 0xcf, 0x48, 0x11, 0x1b, 0xc0, 0x9e, 0x39, 0x93, 0x88, 2105 + 0x22, 0xd6, 0xfd, 0xe5, 0x71, 0x64, 0x92, 0xf4, 0x4f, 0x78, 0x9d, 0x36, 0xdf, 0x3e, 0x3f, 0xbc, 2106 + 0x83, 0xe6, 0x23, 0x62, 0xc2, 0x38, 0x34, 0xc6, 0x48, 0x7f, 0x4e, 0x1f, 0xf2, 0x3a, 0x45, 0xc3, 2107 + 0x87, 0x63, 0x68, 0x8d, 0x56, 0xa8, 0x28, 0x67, 0xf7, 0xff, 0x4f, 0x9e, 0xf3, 0xb5, 0xa0, 0x0f, 2108 + 0xa1, 0xf8, 0x1a, 0x63, 0xfb, 0xf7, 0x05, 0x97, 0x82, 0xdb, 0x59, 0xb3, 0x68, 0xc8, 0xde, 0x8e, 2109 + 0x6a, 0x63, 0xc1, 0xea, 0x36, 0xc8, 0xe2, 0xb8, 0x65, 0x77, 0xdc, 0x7c, 0x07, 0x00, 0x00, 0xff, 2110 + 0xff, 0xba, 0x70, 0xbe, 0x6e, 0x2f, 0x02, 0x00, 0x00, 1612 2111 }