diff --git a/Dockerfile b/Dockerfile index 40dcc6a..0f26b34 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,15 @@ +FROM golang:1.23-alpine AS deps +COPY go.mod go.sum ./ +RUN go mod download + FROM golang:1.23-alpine AS golang-with-curl RUN apk --no-cache add curl FROM golang-with-curl WORKDIR /app +COPY --from=deps /go/pkg/mod /go/pkg/mod COPY go.mod . +COPY go.sum . COPY common common ARG DAY diff --git a/common/env/env.go b/common/env/env.go new file mode 100644 index 0000000..c462ffe --- /dev/null +++ b/common/env/env.go @@ -0,0 +1,26 @@ +package env + +import "os" + +const ( + HttpPrefix = "AOC2024_HTTP_PREFIX" + HttpPort = "AOC2024_HTTP_PORT" + GrpcPort = "AOC2024_GRPC_PORT" +) + +func GetString( + key string, +) string { + return os.Getenv(key) +} + +func GetStringOrDefault( + key string, + def string, +) string { + v := os.Getenv(key) + if v == "" { + return def + } + return v +} diff --git a/common/proto/adventservice.pb.go b/common/proto/adventservice.pb.go new file mode 100644 index 0000000..76fce75 --- /dev/null +++ b/common/proto/adventservice.pb.go @@ -0,0 +1,192 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.2 +// protoc v5.28.3 +// source: common/proto/adventservice.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type InputData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Input string `protobuf:"bytes,1,opt,name=input,proto3" json:"input,omitempty"` +} + +func (x *InputData) Reset() { + *x = InputData{} + mi := &file_common_proto_adventservice_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InputData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InputData) ProtoMessage() {} + +func (x *InputData) ProtoReflect() protoreflect.Message { + mi := &file_common_proto_adventservice_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InputData.ProtoReflect.Descriptor instead. +func (*InputData) Descriptor() ([]byte, []int) { + return file_common_proto_adventservice_proto_rawDescGZIP(), []int{0} +} + +func (x *InputData) GetInput() string { + if x != nil { + return x.Input + } + return "" +} + +type InputResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Result string `protobuf:"bytes,1,opt,name=result,proto3" json:"result,omitempty"` +} + +func (x *InputResponse) Reset() { + *x = InputResponse{} + mi := &file_common_proto_adventservice_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InputResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InputResponse) ProtoMessage() {} + +func (x *InputResponse) ProtoReflect() protoreflect.Message { + mi := &file_common_proto_adventservice_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InputResponse.ProtoReflect.Descriptor instead. +func (*InputResponse) Descriptor() ([]byte, []int) { + return file_common_proto_adventservice_proto_rawDescGZIP(), []int{1} +} + +func (x *InputResponse) GetResult() string { + if x != nil { + return x.Result + } + return "" +} + +var File_common_proto_adventservice_proto protoreflect.FileDescriptor + +var file_common_proto_adventservice_proto_rawDesc = []byte{ + 0x0a, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, + 0x64, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x0d, 0x61, 0x64, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x22, 0x21, 0x0a, 0x09, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x44, 0x61, 0x74, 0x61, 0x12, 0x14, + 0x0a, 0x05, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, + 0x6e, 0x70, 0x75, 0x74, 0x22, 0x27, 0x0a, 0x0d, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x32, 0x9b, 0x01, + 0x0a, 0x0d, 0x41, 0x64, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x44, 0x0a, 0x0a, 0x53, 0x6f, 0x6c, 0x76, 0x65, 0x50, 0x61, 0x72, 0x74, 0x31, 0x12, 0x18, 0x2e, + 0x61, 0x64, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x1c, 0x2e, 0x61, 0x64, 0x76, 0x65, 0x6e, 0x74, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0a, 0x53, 0x6f, 0x6c, 0x76, 0x65, 0x50, 0x61, + 0x72, 0x74, 0x32, 0x12, 0x18, 0x2e, 0x61, 0x64, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x1c, 0x2e, + 0x61, 0x64, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x49, 0x6e, + 0x70, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x37, 0x5a, 0x35, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, + 0x61, 0x6c, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x61, 0x64, 0x76, 0x65, 0x6e, 0x74, 0x6f, 0x66, 0x63, + 0x6f, 0x64, 0x65, 0x32, 0x30, 0x32, 0x34, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_common_proto_adventservice_proto_rawDescOnce sync.Once + file_common_proto_adventservice_proto_rawDescData = file_common_proto_adventservice_proto_rawDesc +) + +func file_common_proto_adventservice_proto_rawDescGZIP() []byte { + file_common_proto_adventservice_proto_rawDescOnce.Do(func() { + file_common_proto_adventservice_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_proto_adventservice_proto_rawDescData) + }) + return file_common_proto_adventservice_proto_rawDescData +} + +var file_common_proto_adventservice_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_common_proto_adventservice_proto_goTypes = []any{ + (*InputData)(nil), // 0: adventservice.InputData + (*InputResponse)(nil), // 1: adventservice.InputResponse +} +var file_common_proto_adventservice_proto_depIdxs = []int32{ + 0, // 0: adventservice.AdventService.SolvePart1:input_type -> adventservice.InputData + 0, // 1: adventservice.AdventService.SolvePart2:input_type -> adventservice.InputData + 1, // 2: adventservice.AdventService.SolvePart1:output_type -> adventservice.InputResponse + 1, // 3: adventservice.AdventService.SolvePart2:output_type -> adventservice.InputResponse + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_common_proto_adventservice_proto_init() } +func file_common_proto_adventservice_proto_init() { + if File_common_proto_adventservice_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_common_proto_adventservice_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_common_proto_adventservice_proto_goTypes, + DependencyIndexes: file_common_proto_adventservice_proto_depIdxs, + MessageInfos: file_common_proto_adventservice_proto_msgTypes, + }.Build() + File_common_proto_adventservice_proto = out.File + file_common_proto_adventservice_proto_rawDesc = nil + file_common_proto_adventservice_proto_goTypes = nil + file_common_proto_adventservice_proto_depIdxs = nil +} diff --git a/common/proto/adventservice.proto b/common/proto/adventservice.proto new file mode 100644 index 0000000..43958ee --- /dev/null +++ b/common/proto/adventservice.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; +package adventservice; + +option go_package = "github.com/terminalnode/adventofcode2024/common/proto"; + + +service AdventService { + rpc SolvePart1 (InputData) returns (InputResponse); + rpc SolvePart2 (InputData) returns (InputResponse); +} + +message InputData { + string input = 1; +} + +message InputResponse { + string result = 1; +} \ No newline at end of file diff --git a/common/proto/adventservice_grpc.pb.go b/common/proto/adventservice_grpc.pb.go new file mode 100644 index 0000000..2d6c0d6 --- /dev/null +++ b/common/proto/adventservice_grpc.pb.go @@ -0,0 +1,159 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.3 +// source: common/proto/adventservice.proto + +package proto + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + AdventService_SolvePart1_FullMethodName = "/adventservice.AdventService/SolvePart1" + AdventService_SolvePart2_FullMethodName = "/adventservice.AdventService/SolvePart2" +) + +// AdventServiceClient is the client API for AdventService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type AdventServiceClient interface { + SolvePart1(ctx context.Context, in *InputData, opts ...grpc.CallOption) (*InputResponse, error) + SolvePart2(ctx context.Context, in *InputData, opts ...grpc.CallOption) (*InputResponse, error) +} + +type adventServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewAdventServiceClient(cc grpc.ClientConnInterface) AdventServiceClient { + return &adventServiceClient{cc} +} + +func (c *adventServiceClient) SolvePart1(ctx context.Context, in *InputData, opts ...grpc.CallOption) (*InputResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(InputResponse) + err := c.cc.Invoke(ctx, AdventService_SolvePart1_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *adventServiceClient) SolvePart2(ctx context.Context, in *InputData, opts ...grpc.CallOption) (*InputResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(InputResponse) + err := c.cc.Invoke(ctx, AdventService_SolvePart2_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AdventServiceServer is the server API for AdventService service. +// All implementations must embed UnimplementedAdventServiceServer +// for forward compatibility. +type AdventServiceServer interface { + SolvePart1(context.Context, *InputData) (*InputResponse, error) + SolvePart2(context.Context, *InputData) (*InputResponse, error) + mustEmbedUnimplementedAdventServiceServer() +} + +// UnimplementedAdventServiceServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedAdventServiceServer struct{} + +func (UnimplementedAdventServiceServer) SolvePart1(context.Context, *InputData) (*InputResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SolvePart1 not implemented") +} +func (UnimplementedAdventServiceServer) SolvePart2(context.Context, *InputData) (*InputResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SolvePart2 not implemented") +} +func (UnimplementedAdventServiceServer) mustEmbedUnimplementedAdventServiceServer() {} +func (UnimplementedAdventServiceServer) testEmbeddedByValue() {} + +// UnsafeAdventServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AdventServiceServer will +// result in compilation errors. +type UnsafeAdventServiceServer interface { + mustEmbedUnimplementedAdventServiceServer() +} + +func RegisterAdventServiceServer(s grpc.ServiceRegistrar, srv AdventServiceServer) { + // If the following call pancis, it indicates UnimplementedAdventServiceServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&AdventService_ServiceDesc, srv) +} + +func _AdventService_SolvePart1_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InputData) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdventServiceServer).SolvePart1(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdventService_SolvePart1_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdventServiceServer).SolvePart1(ctx, req.(*InputData)) + } + return interceptor(ctx, in, info, handler) +} + +func _AdventService_SolvePart2_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InputData) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AdventServiceServer).SolvePart2(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AdventService_SolvePart2_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AdventServiceServer).SolvePart2(ctx, req.(*InputData)) + } + return interceptor(ctx, in, info, handler) +} + +// AdventService_ServiceDesc is the grpc.ServiceDesc for AdventService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var AdventService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "adventservice.AdventService", + HandlerType: (*AdventServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SolvePart1", + Handler: _AdventService_SolvePart1_Handler, + }, + { + MethodName: "SolvePart2", + Handler: _AdventService_SolvePart2_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "common/proto/adventservice.proto", +} diff --git a/common/proto/grpc.go b/common/proto/grpc.go new file mode 100644 index 0000000..5128501 --- /dev/null +++ b/common/proto/grpc.go @@ -0,0 +1,58 @@ +package proto + +import ( + "context" + "fmt" + "github.com/terminalnode/adventofcode2024/common/env" + "github.com/terminalnode/adventofcode2024/common/util" + "google.golang.org/grpc" + "log" + "net" +) + +type server struct { + UnimplementedAdventServiceServer + solvePart1 util.Solution + solvePart2 util.Solution +} + +func CreateGRPCServer( + day int, + part1 util.Solution, + part2 util.Solution, +) *grpc.Server { + port := env.GetStringOrDefault(env.GrpcPort, "50051") + addr := fmt.Sprintf(":%s", port) + + lis, err := net.Listen("tcp", addr) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + + grpcServer := grpc.NewServer() + RegisterAdventServiceServer(grpcServer, &server{solvePart1: part1, solvePart2: part2}) + log.Printf("gRPC server for day #%d starting on port %s", day, port) + + go func() { + if err := grpcServer.Serve(lis); err != nil { + log.Fatalf("Fatal gRPC server error: %v", err) + } + }() + return grpcServer +} + +func (s *server) SolvePart1( + ctx context.Context, + req *InputData, +) (*InputResponse, error) { + result := s.solvePart1(req.Input) + return &InputResponse{Result: result}, nil +} + +func (s *server) SolvePart2( + ctx context.Context, + req *InputData, +) (*InputResponse, error) { + result := s.solvePart2(req.Input) + return &InputResponse{Result: result}, nil +} diff --git a/common/setup.go b/common/setup.go index 950e479..931cdd1 100644 --- a/common/setup.go +++ b/common/setup.go @@ -2,6 +2,7 @@ package common import ( "context" + "github.com/terminalnode/adventofcode2024/common/proto" "github.com/terminalnode/adventofcode2024/common/util" "github.com/terminalnode/adventofcode2024/common/web" "log" @@ -17,12 +18,18 @@ func Setup( part2 util.Solution, ) { httpServer := web.CreateHttpServer(day, part1, part2) + grpcServer := proto.CreateGRPCServer(day, part1, part2) // Open a signal channel, listening for SIGTERM and SIGINT signalChan := make(chan os.Signal, 1) signal.Notify(signalChan, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP) log.Printf("Received signal %s, shutting down...", <-signalChan) + go func() { + grpcServer.GracefulStop() + log.Printf("gRPC server shut down gracefully") + }() + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := httpServer.Shutdown(ctx); err != nil { diff --git a/common/web/http.go b/common/web/http.go index 7d12d6b..468cc02 100644 --- a/common/web/http.go +++ b/common/web/http.go @@ -3,10 +3,10 @@ package web import ( "errors" "fmt" + "github.com/terminalnode/adventofcode2024/common/env" "github.com/terminalnode/adventofcode2024/common/util" "log" "net/http" - "os" ) func CreateHttpServer( @@ -14,17 +14,19 @@ func CreateHttpServer( part1 util.Solution, part2 util.Solution, ) *http.Server { - prefix := os.Getenv("AOC2024_PREFIX") + prefix := env.GetString(env.HttpPrefix) + port := env.GetStringOrDefault(env.HttpPort, "3000") + addr := fmt.Sprintf(":%s", port) - server := &http.Server{Addr: ":3000", Handler: nil} + server := &http.Server{Addr: addr, Handler: nil} addHealthCheckHandlers(prefix) addSolutionHandlers(prefix, day, part1, part2) addUnknownPathHandlers() go func() { - log.Printf("Starting Day #%d service on port 3000", day) + log.Printf("HTTP server for day #%d starting on port %s", day, addr) if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { - log.Fatalf("Fatal server error: %v", err) + log.Fatalf("Fatal HTTP server error: %v", err) } }() return server diff --git a/docker-compose.yml b/docker-compose.yml index a53a9b8..6fe8ab0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '01' } - environment: { AOC2024_PREFIX: 'day01' } + environment: { AOC2024_HTTP_PREFIX: 'day01' } labels: - "traefik.enable=true" - "traefik.http.routers.day01.rule=PathPrefix(`/day01`)" @@ -28,7 +28,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '02' } - environment: { AOC2024_PREFIX: 'day02' } + environment: { AOC2024_HTTP_PREFIX: 'day02' } labels: - "traefik.enable=true" - "traefik.http.routers.day02.rule=PathPrefix(`/day02`)" @@ -43,7 +43,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '03' } - environment: { AOC2024_PREFIX: 'day03' } + environment: { AOC2024_HTTP_PREFIX: 'day03' } labels: - "traefik.enable=true" - "traefik.http.routers.day03.rule=PathPrefix(`/day03`)" @@ -58,7 +58,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '04' } - environment: { AOC2024_PREFIX: 'day04' } + environment: { AOC2024_HTTP_PREFIX: 'day04' } labels: - "traefik.enable=true" - "traefik.http.routers.day04.rule=PathPrefix(`/day04`)" @@ -73,7 +73,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '05' } - environment: { AOC2024_PREFIX: 'day05' } + environment: { AOC2024_HTTP_PREFIX: 'day05' } labels: - "traefik.enable=true" - "traefik.http.routers.day05.rule=PathPrefix(`/day05`)" @@ -88,7 +88,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '06' } - environment: { AOC2024_PREFIX: 'day06' } + environment: { AOC2024_HTTP_PREFIX: 'day06' } labels: - "traefik.enable=true" - "traefik.http.routers.day06.rule=PathPrefix(`/day06`)" @@ -103,7 +103,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '07' } - environment: { AOC2024_PREFIX: 'day07' } + environment: { AOC2024_HTTP_PREFIX: 'day07' } labels: - "traefik.enable=true" - "traefik.http.routers.day07.rule=PathPrefix(`/day07`)" @@ -118,7 +118,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '08' } - environment: { AOC2024_PREFIX: 'day08' } + environment: { AOC2024_HTTP_PREFIX: 'day08' } labels: - "traefik.enable=true" - "traefik.http.routers.day08.rule=PathPrefix(`/day08`)" @@ -133,7 +133,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '09' } - environment: { AOC2024_PREFIX: 'day09' } + environment: { AOC2024_HTTP_PREFIX: 'day09' } labels: - "traefik.enable=true" - "traefik.http.routers.day09.rule=PathPrefix(`/day09`)" @@ -148,7 +148,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '10' } - environment: { AOC2024_PREFIX: 'day10' } + environment: { AOC2024_HTTP_PREFIX: 'day10' } labels: - "traefik.enable=true" - "traefik.http.routers.day10.rule=PathPrefix(`/day10`)" @@ -163,7 +163,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '11' } - environment: { AOC2024_PREFIX: 'day11' } + environment: { AOC2024_HTTP_PREFIX: 'day11' } labels: - "traefik.enable=true" - "traefik.http.routers.day11.rule=PathPrefix(`/day11`)" @@ -178,7 +178,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '12' } - environment: { AOC2024_PREFIX: 'day12' } + environment: { AOC2024_HTTP_PREFIX: 'day12' } labels: - "traefik.enable=true" - "traefik.http.routers.day12.rule=PathPrefix(`/day12`)" @@ -193,7 +193,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '13' } - environment: { AOC2024_PREFIX: 'day13' } + environment: { AOC2024_HTTP_PREFIX: 'day13' } labels: - "traefik.enable=true" - "traefik.http.routers.day13.rule=PathPrefix(`/day13`)" @@ -208,7 +208,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '14' } - environment: { AOC2024_PREFIX: 'day14' } + environment: { AOC2024_HTTP_PREFIX: 'day14' } labels: - "traefik.enable=true" - "traefik.http.routers.day14.rule=PathPrefix(`/day14`)" @@ -223,7 +223,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '15' } - environment: { AOC2024_PREFIX: 'day15' } + environment: { AOC2024_HTTP_PREFIX: 'day15' } labels: - "traefik.enable=true" - "traefik.http.routers.day15.rule=PathPrefix(`/day15`)" @@ -238,7 +238,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '16' } - environment: { AOC2024_PREFIX: 'day16' } + environment: { AOC2024_HTTP_PREFIX: 'day16' } labels: - "traefik.enable=true" - "traefik.http.routers.day16.rule=PathPrefix(`/day16`)" @@ -253,7 +253,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '17' } - environment: { AOC2024_PREFIX: 'day17' } + environment: { AOC2024_HTTP_PREFIX: 'day17' } labels: - "traefik.enable=true" - "traefik.http.routers.day17.rule=PathPrefix(`/day17`)" @@ -268,7 +268,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '18' } - environment: { AOC2024_PREFIX: 'day18' } + environment: { AOC2024_HTTP_PREFIX: 'day18' } labels: - "traefik.enable=true" - "traefik.http.routers.day18.rule=PathPrefix(`/day18`)" @@ -283,7 +283,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '19' } - environment: { AOC2024_PREFIX: 'day19' } + environment: { AOC2024_HTTP_PREFIX: 'day19' } labels: - "traefik.enable=true" - "traefik.http.routers.day19.rule=PathPrefix(`/day19`)" @@ -298,7 +298,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '20' } - environment: { AOC2024_PREFIX: 'day20' } + environment: { AOC2024_HTTP_PREFIX: 'day20' } labels: - "traefik.enable=true" - "traefik.http.routers.day20.rule=PathPrefix(`/day20`)" @@ -313,7 +313,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '21' } - environment: { AOC2024_PREFIX: 'day21' } + environment: { AOC2024_HTTP_PREFIX: 'day21' } labels: - "traefik.enable=true" - "traefik.http.routers.day21.rule=PathPrefix(`/day21`)" @@ -328,7 +328,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '22' } - environment: { AOC2024_PREFIX: 'day22' } + environment: { AOC2024_HTTP_PREFIX: 'day22' } labels: - "traefik.enable=true" - "traefik.http.routers.day22.rule=PathPrefix(`/day22`)" @@ -343,7 +343,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '23' } - environment: { AOC2024_PREFIX: 'day23' } + environment: { AOC2024_HTTP_PREFIX: 'day23' } labels: - "traefik.enable=true" - "traefik.http.routers.day23.rule=PathPrefix(`/day23`)" @@ -358,7 +358,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '24' } - environment: { AOC2024_PREFIX: 'day24' } + environment: { AOC2024_HTTP_PREFIX: 'day24' } labels: - "traefik.enable=true" - "traefik.http.routers.day24.rule=PathPrefix(`/day24`)" @@ -373,7 +373,7 @@ services: context: . dockerfile: Dockerfile args: { DAY: '25' } - environment: { AOC2024_PREFIX: 'day25' } + environment: { AOC2024_HTTP_PREFIX: 'day25' } labels: - "traefik.enable=true" - "traefik.http.routers.day25.rule=PathPrefix(`/day25`)" diff --git a/go.mod b/go.mod index c58c34f..4a38521 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,15 @@ module github.com/terminalnode/adventofcode2024 go 1.23.3 + +require ( + google.golang.org/grpc v1.68.1 + google.golang.org/protobuf v1.35.2 +) + +require ( + golang.org/x/net v0.29.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..2896864 --- /dev/null +++ b/go.sum @@ -0,0 +1,16 @@ +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0= +google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=