Skip to content

Commit 8ac246f

Browse files
committed
protocol, protocol/dataunit: protocol.Server
1 parent 1dd4de0 commit 8ac246f

File tree

3 files changed

+96
-10
lines changed

3 files changed

+96
-10
lines changed

protocol/dataunit/conn.go

+6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ type Writer interface {
2424
WriteDataUnit([]byte) error
2525
}
2626

27+
type writerFunc func(data []byte) error
28+
29+
func (f writerFunc) WriteDataUnit(data []byte) error {
30+
return f(data)
31+
}
32+
2733
// Conn is the interface implemented by any type that can read and write EPP data units.
2834
// Concurrent operations on a Conn are implementation-specific and should
2935
// be protected by a synchronization mechanism.

protocol/dataunit/server.go

+7-10
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@ import (
55
)
66

77
// Server provides an ordered queue of client requests coupled with a [Writer]
8-
// to respond to the request. The Writer returned from ServeDataUnit can be called once.
9-
// Calling WriteDataUnit more than once is undefined.
8+
// to respond to the request.
109
// Server enforces ordering of responses, writing each response in the same
1110
// order as the requests received from the client.
12-
// A Server is safe to call from multiple goroutines, and each client request
13-
// may be handled in a separate goroutine.
11+
// ServeDataUnit is safe to be called from multiple goroutines.
1412
type Server struct {
1513
// reading protects Conn and reading
1614
reading sync.Mutex
@@ -24,6 +22,11 @@ type Server struct {
2422
Conn Conn
2523
}
2624

25+
// ServeDataUnit reads one data unit from the client and provides a [Writer] to respond.
26+
// The returned Writer can only be called once. The returned Writer will always
27+
// be non-nil, so the caller can respond to a malformed client request.
28+
// ServeDataUnit is safe to be called from multiple goroutines, and each client request
29+
// may be handled in a separate goroutine.
2730
func (s *Server) ServeDataUnit() ([]byte, Writer, error) {
2831
s.reading.Lock()
2932
defer s.reading.Unlock()
@@ -92,9 +95,3 @@ type transaction struct {
9295
res []byte
9396
err chan error
9497
}
95-
96-
type writerFunc func(data []byte) error
97-
98-
func (f writerFunc) WriteDataUnit(data []byte) error {
99-
return f(data)
100-
}

protocol/server.go

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package protocol
2+
3+
import (
4+
"github.com/domainr/epp2/protocol/dataunit"
5+
"github.com/domainr/epp2/schema"
6+
"github.com/domainr/epp2/schema/epp"
7+
)
8+
9+
// Writer is the interface implemented by any type that can write an EPP message body.
10+
type Writer interface {
11+
WriteEPP(epp.Body) error
12+
}
13+
14+
type writerFunc func(body epp.Body) error
15+
16+
func (f writerFunc) WriteEPP(body epp.Body) error {
17+
return f(body)
18+
}
19+
20+
// Server is a low-level server for the Extensible Provisioning Protocol (EPP)
21+
// as defined in [RFC 5730]. A Server is safe to use from multiple goroutines.
22+
//
23+
// [RFC 5730]: https://datatracker.ietf.org/doc/rfc5730/
24+
type Server interface {
25+
// ServeEPP provides an client EPP request and a mechanism to respond to the request.
26+
// It blocks until a response is received or the underlying connection is closed.
27+
// The returned [Writer] should only be used once. The returned Writer will always
28+
// be non-nil, so the caller can respond to a malformed client request.
29+
ServeEPP() (epp.Body, Writer, error)
30+
31+
// Close closes the connection.
32+
Close() error
33+
}
34+
35+
type server struct {
36+
server dataunit.Server
37+
coder coder
38+
}
39+
40+
// Serve services conn as an EPP server, sending greeting as the initial <greeting>
41+
// message to the client.
42+
// EPP requests from the client will be decoded using [schemas.Schema] schemas.
43+
// If no schemas are provided, a set of reasonable defaults will be used.
44+
func Serve(conn dataunit.Conn, greeting epp.Body, schemas ...schema.Schema) (Server, error) {
45+
s := newServer(conn, schemas)
46+
// Send the initial <greeting> to the client.
47+
data, err := s.coder.marshalXML(greeting)
48+
if err != nil {
49+
return nil, err
50+
}
51+
return s, conn.WriteDataUnit(data)
52+
}
53+
54+
func newServer(conn dataunit.Conn, schemas schema.Schemas) *server {
55+
if len(schemas) == 0 {
56+
schemas = DefaultSchemas()
57+
}
58+
return &server{
59+
server: dataunit.Server{Conn: conn},
60+
coder: coder{schemas},
61+
}
62+
}
63+
64+
// Close closes the connection, interrupting any in-flight requests.
65+
func (s *server) Close() error {
66+
return s.server.Conn.Close()
67+
}
68+
69+
func (s *server) ServeEPP() (epp.Body, Writer, error) {
70+
data, w, err := s.server.ServeDataUnit()
71+
f := writerFunc(func(body epp.Body) error {
72+
data, err := s.coder.marshalXML(body)
73+
if err != nil {
74+
return err
75+
}
76+
return w.WriteDataUnit(data)
77+
})
78+
if err != nil {
79+
return nil, f, err
80+
}
81+
body, err := s.coder.umarshalXML(data)
82+
return body, f, err
83+
}

0 commit comments

Comments
 (0)