aboutsummaryrefslogtreecommitdiff
path: root/receivepack/receivepack.go
diff options
context:
space:
mode:
Diffstat (limited to 'receivepack/receivepack.go')
-rw-r--r--receivepack/receivepack.go94
1 files changed, 94 insertions, 0 deletions
diff --git a/receivepack/receivepack.go b/receivepack/receivepack.go
new file mode 100644
index 00000000..9f4a582b
--- /dev/null
+++ b/receivepack/receivepack.go
@@ -0,0 +1,94 @@
+package receivepack
+
+import (
+ "context"
+ "io"
+
+ "codeberg.org/lindenii/furgit/format/pktline"
+ common "codeberg.org/lindenii/furgit/protocol/v0v1/server"
+ protoreceive "codeberg.org/lindenii/furgit/protocol/v0v1/server/receivepack"
+ "codeberg.org/lindenii/furgit/receivepack/internal/service"
+)
+
+// ReceivePack serves one receive-pack session over r/w.
+func ReceivePack(
+ ctx context.Context,
+ w pktline.WriteFlusher,
+ e io.Writer,
+ r io.Reader,
+ opts Options,
+) error {
+ _ = e // TODO: Use stderr/progress sink explicitly as hook/progress behavior expands.
+
+ err := validateOptions(opts)
+ if err != nil {
+ return err
+ }
+
+ version := parseVersion(opts.GitProtocol)
+
+ base := common.NewSession(r, w, common.Options{
+ Version: version,
+ Algorithm: opts.Algorithm,
+ })
+
+ protoSession := protoreceive.NewSession(base, protoreceive.Capabilities{
+ ReportStatus: true,
+ ReportStatusV2: true,
+ DeleteRefs: true,
+ SideBand64K: true,
+ Quiet: true,
+ Atomic: true,
+ OfsDelta: true,
+ PushOptions: true,
+ ObjectFormat: opts.Algorithm,
+ // TODO: PushCertNonce, SessionID, Agent, whatever.
+ })
+
+ refs, err := advertisedRefs(opts)
+ if err != nil {
+ return err
+ }
+
+ err = protoSession.AdvertiseRefs(common.Advertisement{Refs: refs})
+ if err != nil {
+ return err
+ }
+
+ req, err := protoSession.ReadRequest()
+ if err != nil {
+ return err
+ }
+
+ serviceReq := &service.Request{
+ Commands: translateCommands(req.Commands),
+ PushOptions: append([]string(nil), req.PushOptions...),
+ DeleteOnly: req.DeleteOnly,
+ PackExpected: req.PackExpected,
+ Pack: r,
+ }
+
+ svc := service.New(service.Options{
+ Algorithm: opts.Algorithm,
+ Refs: opts.Refs,
+ ExistingObjects: opts.ExistingObjects,
+ ObjectsRoot: opts.ObjectsRoot,
+ })
+
+ result, err := svc.Execute(ctx, serviceReq)
+ if err != nil {
+ return err
+ }
+
+ protoResult := translateResult(result)
+
+ if req.Capabilities.ReportStatusV2 {
+ return protoSession.WriteReportStatusV2(protoResult)
+ }
+
+ if req.Capabilities.ReportStatus {
+ return protoSession.WriteReportStatus(protoResult)
+ }
+
+ return nil
+}