diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..e29c414 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 0000000..ab4cd99 --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/go.mod b/go.mod index 788cf01..50afde5 100644 --- a/go.mod +++ b/go.mod @@ -77,6 +77,7 @@ require ( github.com/kennygrant/sanitize v1.2.4 // indirect github.com/klauspost/compress v1.17.8 // indirect github.com/leodido/go-urn v1.2.4 // indirect + github.com/lib/pq v1.10.9 // indirect github.com/lukesampson/figlet v0.0.0-20190211215653-8a3ef4a6ac42 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect diff --git a/go.sum b/go.sum index 0ce9486..0846c67 100644 --- a/go.sum +++ b/go.sum @@ -233,6 +233,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lukesampson/figlet v0.0.0-20190211215653-8a3ef4a6ac42 h1:UtyD+eBVdLYSj5/pjfSR6mtnzMgIiOVcFT024G2l4CY= github.com/lukesampson/figlet v0.0.0-20190211215653-8a3ef4a6ac42/go.mod h1:/peI0OaxVYh7fzA72CD7rUsyGVdF7sCiFw7GcYqOcCw= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= diff --git a/pkg/http/api/command.go b/pkg/http/api/command.go index f23088f..536af84 100644 --- a/pkg/http/api/command.go +++ b/pkg/http/api/command.go @@ -52,9 +52,6 @@ func invokeCommand(c *fiber.Ctx) error { if err != nil { return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } else { - if !out.IsDelivered { - log.Debug().Str("id", command).Str("method", method).Msg("Invoking command from HTTP Gateway... failed, delivery not confirmed") - } c.Set(fiber.HeaderContentType, out.ContentType) return c.Status(int(out.Status)).Send(out.Payload) } diff --git a/pkg/http/api/index.go b/pkg/http/api/index.go index 2b11f17..a4e4d7c 100644 --- a/pkg/http/api/index.go +++ b/pkg/http/api/index.go @@ -1,6 +1,7 @@ package api import ( + "git.solsynth.dev/hypernet/nexus/pkg/http/ws" "github.com/gofiber/contrib/websocket" "github.com/gofiber/fiber/v2" ) @@ -22,7 +23,7 @@ func MapAPIs(app *fiber.App) { return err }*/ return c.Next() - }).Get("/ws", websocket.New(listenWebsocket)) + }).Get("/ws", websocket.New(ws.Listen)) app.All("/cgi/:command", invokeCommand) } diff --git a/pkg/internal/services/connections.go b/pkg/http/ws/connections.go similarity index 99% rename from pkg/internal/services/connections.go rename to pkg/http/ws/connections.go index e95a305..a803867 100644 --- a/pkg/internal/services/connections.go +++ b/pkg/http/ws/connections.go @@ -1,4 +1,4 @@ -package services +package ws import ( "math/rand" diff --git a/pkg/http/api/ws.go b/pkg/http/ws/ws.go similarity index 91% rename from pkg/http/api/ws.go rename to pkg/http/ws/ws.go index 812c3b6..50d9b10 100644 --- a/pkg/http/api/ws.go +++ b/pkg/http/ws/ws.go @@ -1,8 +1,7 @@ -package api +package ws import ( "git.solsynth.dev/hypernet/nexus/pkg/internal/models" - "git.solsynth.dev/hypernet/nexus/pkg/internal/services" "git.solsynth.dev/hypernet/nexus/pkg/nex" "github.com/gofiber/contrib/websocket" jsoniter "github.com/json-iterator/go" @@ -10,11 +9,11 @@ import ( "github.com/spf13/viper" ) -func listenWebsocket(c *websocket.Conn) { +func Listen(c *websocket.Conn) { user := c.Locals("user").(models.Account) // Push connection - clientId := services.ClientRegister(user, c) + clientId := ClientRegister(user, c) log.Debug(). Uint("user", user.ID). Uint64("clientId", clientId). @@ -78,7 +77,7 @@ func listenWebsocket(c *websocket.Conn) { } // Pop connection - services.ClientUnregister(user, clientId) + ClientUnregister(user, clientId) log.Debug(). Uint("user", user.ID). Uint64("clientId", clientId). diff --git a/pkg/internal/database/allocator.go b/pkg/internal/database/allocator.go new file mode 100644 index 0000000..b403ba7 --- /dev/null +++ b/pkg/internal/database/allocator.go @@ -0,0 +1,39 @@ +package database + +import ( + "fmt" + "github.com/samber/lo" + "github.com/spf13/viper" + "strings" +) + +func AllocDatabase(name string) (string, error) { + // Disabled + if Kdb == nil { + return "host=localhost", fmt.Errorf("database feature is disabled") + } + + var connString []string + connString = strings.Split(viper.GetString("database.dsn"), " ") + connString = lo.Filter(connString, func(item string, _ int) bool { + return !strings.HasPrefix(item, "dbname=") + }) + + name = viper.GetString("database.prefix") + name + + var exists bool + if err := Kdb.QueryRow("SELECT EXISTS(SELECT datname FROM pg_catalog.pg_database WHERE datname = $1)", name).Scan(&exists); err != nil { + return strings.Join(connString, " "), nil + } + + if !exists { + _, err := Kdb.Exec("CREATE DATABASE " + name) + if err != nil { + return strings.Join(connString, " "), err + } + } + + connString = append(connString, "dbname="+name) + + return strings.Join(connString, " "), nil +} diff --git a/pkg/internal/database/connect.go b/pkg/internal/database/connect.go new file mode 100644 index 0000000..8dd5df2 --- /dev/null +++ b/pkg/internal/database/connect.go @@ -0,0 +1,16 @@ +package database + +import ( + "database/sql" + _ "github.com/lib/pq" +) + +var Kdb *sql.DB + +func Connect(str string) (*sql.DB, error) { + db, err := sql.Open("postgres", str) + if err == nil { + Kdb = db + } + return db, err +} diff --git a/pkg/internal/grpc/database.go b/pkg/internal/grpc/database.go new file mode 100644 index 0000000..38d25f4 --- /dev/null +++ b/pkg/internal/grpc/database.go @@ -0,0 +1,20 @@ +package grpc + +import ( + "context" + "git.solsynth.dev/hypernet/nexus/pkg/internal/database" + "git.solsynth.dev/hypernet/nexus/pkg/proto" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (v *Server) AllocDatabase(ctx context.Context, request *proto.AllocDatabaseRequest) (*proto.AllocDatabaseResponse, error) { + dsn, err := database.AllocDatabase(request.GetName()) + if err != nil { + return nil, status.Errorf(codes.Internal, err.Error()) + } + return &proto.AllocDatabaseResponse{ + IsSuccess: true, + Dsn: dsn, + }, nil +} diff --git a/pkg/internal/grpc/health.go b/pkg/internal/grpc/health.go index 5994d65..d8d2721 100644 --- a/pkg/internal/grpc/health.go +++ b/pkg/internal/grpc/health.go @@ -7,13 +7,13 @@ import ( health "google.golang.org/grpc/health/grpc_health_v1" ) -func (v *GrpcServer) Check(ctx context.Context, request *health.HealthCheckRequest) (*health.HealthCheckResponse, error) { +func (v *Server) Check(ctx context.Context, request *health.HealthCheckRequest) (*health.HealthCheckResponse, error) { return &health.HealthCheckResponse{ Status: health.HealthCheckResponse_SERVING, }, nil } -func (v *GrpcServer) Watch(request *health.HealthCheckRequest, server health.Health_WatchServer) error { +func (v *Server) Watch(request *health.HealthCheckRequest, server health.Health_WatchServer) error { for { if server.Send(&health.HealthCheckResponse{ Status: health.HealthCheckResponse_SERVING, diff --git a/pkg/internal/grpc/server.go b/pkg/internal/grpc/server.go index 41579c4..3cf5a62 100644 --- a/pkg/internal/grpc/server.go +++ b/pkg/internal/grpc/server.go @@ -14,19 +14,22 @@ import ( health "google.golang.org/grpc/health/grpc_health_v1" ) -type GrpcServer struct { +type Server struct { + proto.UnimplementedDatabaseControllerServer proto.UnimplementedStreamControllerServer + health.UnimplementedHealthServer srv *grpc.Server } -func NewServer() *GrpcServer { - server := &GrpcServer{ +func NewServer() *Server { + server := &Server{ srv: grpc.NewServer(), } proto.RegisterServiceDirectoryServer(server.srv, &directory.ServiceRpcServer{}) proto.RegisterCommandControllerServer(server.srv, &directory.CommandRpcServer{}) + proto.RegisterDatabaseControllerServer(server.srv, server) proto.RegisterStreamControllerServer(server.srv, server) health.RegisterHealthServer(server.srv, server) @@ -35,7 +38,7 @@ func NewServer() *GrpcServer { return server } -func (v *GrpcServer) Listen() error { +func (v *Server) Listen() error { listener, err := net.Listen("tcp", viper.GetString("grpc_bind")) if err != nil { return err diff --git a/pkg/internal/grpc/stream.go b/pkg/internal/grpc/stream.go index fa87bf8..18ce1fe 100644 --- a/pkg/internal/grpc/stream.go +++ b/pkg/internal/grpc/stream.go @@ -3,27 +3,27 @@ package grpc import ( "context" "fmt" + "git.solsynth.dev/hypernet/nexus/pkg/http/ws" - "git.solsynth.dev/hypernet/nexus/pkg/internal/services" "git.solsynth.dev/hypernet/nexus/pkg/proto" "github.com/samber/lo" ) -func (v *GrpcServer) CountStreamConnection(ctx context.Context, request *proto.CountConnectionRequest) (*proto.CountConnectionResponse, error) { - out := services.ClientCount(uint(request.GetUserId())) +func (v *Server) CountStreamConnection(ctx context.Context, request *proto.CountConnectionRequest) (*proto.CountConnectionResponse, error) { + out := ws.ClientCount(uint(request.GetUserId())) return &proto.CountConnectionResponse{ Count: int64(out), }, nil } -func (v *GrpcServer) PushStream(ctx context.Context, request *proto.PushStreamRequest) (*proto.PushStreamResponse, error) { +func (v *Server) PushStream(ctx context.Context, request *proto.PushStreamRequest) (*proto.PushStreamResponse, error) { var cnt int var success int var errs []error if request.UserId != nil { - cnt, success, errs = services.WebsocketPush(uint(request.GetUserId()), request.GetBody()) + cnt, success, errs = ws.WebsocketPush(uint(request.GetUserId()), request.GetBody()) } else if request.ClientId != nil { - cnt, success, errs = services.WebsocketPushDirect(request.GetClientId(), request.GetBody()) + cnt, success, errs = ws.WebsocketPushDirect(request.GetClientId(), request.GetBody()) } else { return nil, fmt.Errorf("you must give one of the user id or client id") } @@ -47,12 +47,12 @@ func (v *GrpcServer) PushStream(ctx context.Context, request *proto.PushStreamRe }, nil } -func (v *GrpcServer) PushStreamBatch(ctx context.Context, request *proto.PushStreamBatchRequest) (*proto.PushStreamResponse, error) { +func (v *Server) PushStreamBatch(ctx context.Context, request *proto.PushStreamBatchRequest) (*proto.PushStreamResponse, error) { var cnt int var success int var errs []error if len(request.UserId) != 0 { - cnt, success, errs = services.WebsocketPushBatch( + cnt, success, errs = ws.WebsocketPushBatch( lo.Map(request.GetUserId(), func(item uint64, idx int) uint { return uint(item) }, @@ -60,7 +60,7 @@ func (v *GrpcServer) PushStreamBatch(ctx context.Context, request *proto.PushStr ) } if len(request.ClientId) != 0 { - cCnt, cSuccess, cErrs := services.WebsocketPushBatchDirect(request.GetClientId(), request.GetBody()) + cCnt, cSuccess, cErrs := ws.WebsocketPushBatchDirect(request.GetClientId(), request.GetBody()) cnt += cCnt success += cSuccess errs = append(errs, cErrs...) diff --git a/pkg/main.go b/pkg/main.go index 4176545..47bf991 100644 --- a/pkg/main.go +++ b/pkg/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "git.solsynth.dev/hypernet/nexus/pkg/internal/database" "github.com/fatih/color" "os" "os/signal" @@ -30,7 +31,7 @@ func main() { | |\ | __/> <| |_| \__ \ |_| \_|\___/_/\_\\__,_|___/`)) fmt.Printf("%s v%s\n", color.New(color.FgHiYellow).Add(color.Bold).Sprintf("Hypernet.Nexus"), pkg.AppVersion) - fmt.Printf("The core component of Hypernet (Solar Network)\n") + fmt.Printf("The next-generation web application framework\n") color.HiBlack("=====================================================\n") // Configure settings @@ -44,6 +45,20 @@ func main() { log.Panic().Err(err).Msg("An error occurred when loading settings.") } + // Connect to database + if db, err := database.Connect(viper.GetString("database.dsn")); err != nil { + log.Error().Err(err).Msg("An error occurred when connecting to database. Database related features will be disabled.") + } else { + var version string + err := db.QueryRow("SELECT version()").Scan(&version) + if err != nil { + log.Error().Err(err).Msg("An error occurred when querying database version. Database related features will be disabled.") + database.Kdb = nil + } else { + log.Info().Str("version", version).Msg("Connected to database") + } + } + // Server go server.NewServer().Listen() diff --git a/pkg/nex/cruda/allocator.go b/pkg/nex/cruda/allocator.go new file mode 100644 index 0000000..8489021 --- /dev/null +++ b/pkg/nex/cruda/allocator.go @@ -0,0 +1,20 @@ +package cruda + +import ( + "context" + "git.solsynth.dev/hypernet/nexus/pkg/proto" + "google.golang.org/grpc/metadata" +) + +func (v *CudaConn) AllocDatabase(name string) (string, error) { + conn := v.Conn.GetNexusGrpcConn() + ctx := context.Background() + ctx = metadata.AppendToOutgoingContext(ctx, "client_id", v.Conn.Info.Id) + out, err := proto.NewDatabaseControllerClient(conn).AllocDatabase(ctx, &proto.AllocDatabaseRequest{ + Name: name, + }) + if err != nil || !out.GetIsSuccess() { + return "", err + } + return out.GetDsn(), nil +} diff --git a/pkg/nex/cruda/allocator_test.go b/pkg/nex/cruda/allocator_test.go new file mode 100644 index 0000000..5962b75 --- /dev/null +++ b/pkg/nex/cruda/allocator_test.go @@ -0,0 +1,33 @@ +package cruda_test + +import ( + "fmt" + "git.solsynth.dev/hypernet/nexus/pkg/nex" + "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" + "git.solsynth.dev/hypernet/nexus/pkg/proto" + "testing" +) + +func TestAllocDatabase(t *testing.T) { + conn, err := nex.NewNexusConn("127.0.0.1:7001", &proto.ServiceInfo{ + Id: "alloc01", + Type: "alloc", + Label: "Allocator", + GrpcAddr: "127.0.0.1:6001", + HttpAddr: nil, + }) + if err != nil { + t.Fatal(fmt.Errorf("unable to connect nexus: %v", err)) + } + + if err := conn.RegisterService(); err != nil { + t.Fatal(fmt.Errorf("unable to register service: %v", err)) + } + + cc := cruda.NewCudaConn(conn) + dsn, err := cc.AllocDatabase("test") + if err != nil { + t.Fatal(fmt.Errorf("unable to allocate database: %v", err)) + } + t.Log(fmt.Sprintf("Allocated database: %s", dsn)) +} diff --git a/pkg/nex/cruda/conn.go b/pkg/nex/cruda/conn.go new file mode 100644 index 0000000..7d10e5e --- /dev/null +++ b/pkg/nex/cruda/conn.go @@ -0,0 +1,13 @@ +package cruda + +import "git.solsynth.dev/hypernet/nexus/pkg/nex" + +type CudaConn struct { + Conn *nex.Conn +} + +func NewCudaConn(conn *nex.Conn) *CudaConn { + return &CudaConn{ + Conn: conn, + } +} diff --git a/pkg/internal/gap/net.go b/pkg/nex/net.go similarity index 95% rename from pkg/internal/gap/net.go rename to pkg/nex/net.go index d618851..74c257f 100644 --- a/pkg/internal/gap/net.go +++ b/pkg/nex/net.go @@ -1,4 +1,4 @@ -package gap +package nex import "net" diff --git a/pkg/proto/database.pb.go b/pkg/proto/database.pb.go new file mode 100644 index 0000000..4535c1f --- /dev/null +++ b/pkg/proto/database.pb.go @@ -0,0 +1,193 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.2 +// source: database.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 AllocDatabaseRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *AllocDatabaseRequest) Reset() { + *x = AllocDatabaseRequest{} + mi := &file_database_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AllocDatabaseRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AllocDatabaseRequest) ProtoMessage() {} + +func (x *AllocDatabaseRequest) ProtoReflect() protoreflect.Message { + mi := &file_database_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 AllocDatabaseRequest.ProtoReflect.Descriptor instead. +func (*AllocDatabaseRequest) Descriptor() ([]byte, []int) { + return file_database_proto_rawDescGZIP(), []int{0} +} + +func (x *AllocDatabaseRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type AllocDatabaseResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IsSuccess bool `protobuf:"varint,1,opt,name=is_success,json=isSuccess,proto3" json:"is_success,omitempty"` + Dsn string `protobuf:"bytes,2,opt,name=dsn,proto3" json:"dsn,omitempty"` +} + +func (x *AllocDatabaseResponse) Reset() { + *x = AllocDatabaseResponse{} + mi := &file_database_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AllocDatabaseResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AllocDatabaseResponse) ProtoMessage() {} + +func (x *AllocDatabaseResponse) ProtoReflect() protoreflect.Message { + mi := &file_database_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 AllocDatabaseResponse.ProtoReflect.Descriptor instead. +func (*AllocDatabaseResponse) Descriptor() ([]byte, []int) { + return file_database_proto_rawDescGZIP(), []int{1} +} + +func (x *AllocDatabaseResponse) GetIsSuccess() bool { + if x != nil { + return x.IsSuccess + } + return false +} + +func (x *AllocDatabaseResponse) GetDsn() string { + if x != nil { + return x.Dsn + } + return "" +} + +var File_database_proto protoreflect.FileDescriptor + +var file_database_proto_rawDesc = []byte{ + 0x0a, 0x0e, 0x64, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2a, 0x0a, 0x14, 0x41, 0x6c, 0x6c, 0x6f, 0x63, + 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x22, 0x48, 0x0a, 0x15, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x44, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, + 0x69, 0x73, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x69, 0x73, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x64, + 0x73, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x73, 0x6e, 0x32, 0x62, 0x0a, + 0x12, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x12, 0x4c, 0x0a, 0x0d, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x44, 0x61, 0x74, 0x61, + 0x62, 0x61, 0x73, 0x65, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x6c, 0x6c, + 0x6f, 0x63, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x44, + 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_database_proto_rawDescOnce sync.Once + file_database_proto_rawDescData = file_database_proto_rawDesc +) + +func file_database_proto_rawDescGZIP() []byte { + file_database_proto_rawDescOnce.Do(func() { + file_database_proto_rawDescData = protoimpl.X.CompressGZIP(file_database_proto_rawDescData) + }) + return file_database_proto_rawDescData +} + +var file_database_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_database_proto_goTypes = []any{ + (*AllocDatabaseRequest)(nil), // 0: proto.AllocDatabaseRequest + (*AllocDatabaseResponse)(nil), // 1: proto.AllocDatabaseResponse +} +var file_database_proto_depIdxs = []int32{ + 0, // 0: proto.DatabaseController.AllocDatabase:input_type -> proto.AllocDatabaseRequest + 1, // 1: proto.DatabaseController.AllocDatabase:output_type -> proto.AllocDatabaseResponse + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] 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_database_proto_init() } +func file_database_proto_init() { + if File_database_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_database_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_database_proto_goTypes, + DependencyIndexes: file_database_proto_depIdxs, + MessageInfos: file_database_proto_msgTypes, + }.Build() + File_database_proto = out.File + file_database_proto_rawDesc = nil + file_database_proto_goTypes = nil + file_database_proto_depIdxs = nil +} diff --git a/pkg/proto/database.proto b/pkg/proto/database.proto new file mode 100644 index 0000000..f7b4622 --- /dev/null +++ b/pkg/proto/database.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +option go_package = ".;proto"; + +package proto; + +service DatabaseController { + rpc AllocDatabase(AllocDatabaseRequest) returns (AllocDatabaseResponse) {} +} + +message AllocDatabaseRequest { + string name = 1; +} + +message AllocDatabaseResponse { + bool is_success = 1; + string dsn = 2; +} \ No newline at end of file diff --git a/pkg/proto/database_grpc.pb.go b/pkg/proto/database_grpc.pb.go new file mode 100644 index 0000000..c7b8c3b --- /dev/null +++ b/pkg/proto/database_grpc.pb.go @@ -0,0 +1,121 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.2 +// source: database.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 ( + DatabaseController_AllocDatabase_FullMethodName = "/proto.DatabaseController/AllocDatabase" +) + +// DatabaseControllerClient is the client API for DatabaseController 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 DatabaseControllerClient interface { + AllocDatabase(ctx context.Context, in *AllocDatabaseRequest, opts ...grpc.CallOption) (*AllocDatabaseResponse, error) +} + +type databaseControllerClient struct { + cc grpc.ClientConnInterface +} + +func NewDatabaseControllerClient(cc grpc.ClientConnInterface) DatabaseControllerClient { + return &databaseControllerClient{cc} +} + +func (c *databaseControllerClient) AllocDatabase(ctx context.Context, in *AllocDatabaseRequest, opts ...grpc.CallOption) (*AllocDatabaseResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AllocDatabaseResponse) + err := c.cc.Invoke(ctx, DatabaseController_AllocDatabase_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DatabaseControllerServer is the server API for DatabaseController service. +// All implementations must embed UnimplementedDatabaseControllerServer +// for forward compatibility. +type DatabaseControllerServer interface { + AllocDatabase(context.Context, *AllocDatabaseRequest) (*AllocDatabaseResponse, error) + mustEmbedUnimplementedDatabaseControllerServer() +} + +// UnimplementedDatabaseControllerServer 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 UnimplementedDatabaseControllerServer struct{} + +func (UnimplementedDatabaseControllerServer) AllocDatabase(context.Context, *AllocDatabaseRequest) (*AllocDatabaseResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllocDatabase not implemented") +} +func (UnimplementedDatabaseControllerServer) mustEmbedUnimplementedDatabaseControllerServer() {} +func (UnimplementedDatabaseControllerServer) testEmbeddedByValue() {} + +// UnsafeDatabaseControllerServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to DatabaseControllerServer will +// result in compilation errors. +type UnsafeDatabaseControllerServer interface { + mustEmbedUnimplementedDatabaseControllerServer() +} + +func RegisterDatabaseControllerServer(s grpc.ServiceRegistrar, srv DatabaseControllerServer) { + // If the following call pancis, it indicates UnimplementedDatabaseControllerServer 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(&DatabaseController_ServiceDesc, srv) +} + +func _DatabaseController_AllocDatabase_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AllocDatabaseRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DatabaseControllerServer).AllocDatabase(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DatabaseController_AllocDatabase_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DatabaseControllerServer).AllocDatabase(ctx, req.(*AllocDatabaseRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// DatabaseController_ServiceDesc is the grpc.ServiceDesc for DatabaseController service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var DatabaseController_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "proto.DatabaseController", + HandlerType: (*DatabaseControllerServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AllocDatabase", + Handler: _DatabaseController_AllocDatabase_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "database.proto", +} diff --git a/settings.toml b/settings.toml index 40794bb..c165e57 100644 --- a/settings.toml +++ b/settings.toml @@ -21,8 +21,8 @@ access_token_duration = 300 refresh_token_duration = 2592000 [database] -dsn = "host=localhost user=postgres password=password dbname=hy_dealer port=5432 sslmode=disable" -prefix = "dealer_" +dsn = "host=localhost user=postgres dbname=postgres password=password port=5432 sslmode=disable" +prefix = "sn_" [scraper] user-agent = "SolarBot/1.0" \ No newline at end of file