Blob


1 package p9p
3 import "context"
5 // Handler defines an interface for 9p message handlers. A handler
6 // implementation could be used to intercept calls of all types before sending
7 // them to the next handler.
8 type Handler interface {
9 Handle(ctx context.Context, msg Message) (Message, error)
11 // TODO(stevvooe): Right now, this interface is functianally identical to
12 // roundtripper. If we find that this is sufficient on the server-side, we
13 // may unify the types. For now, we leave them separated to differentiate
14 // between them.
15 }
17 // HandlerFunc is a convenience type for defining inline handlers.
18 type HandlerFunc func(ctx context.Context, msg Message) (Message, error)
20 // Handle implements the requirements for the Handler interface.
21 func (fn HandlerFunc) Handle(ctx context.Context, msg Message) (Message, error) {
22 return fn(ctx, msg)
23 }
25 // Dispatch returns a handler that dispatches messages to the target session.
26 // No concurrency is managed by the returned handler. It simply turns messages
27 // into function calls on the session.
28 func Dispatch(session Session) Handler {
29 return HandlerFunc(func(ctx context.Context, msg Message) (Message, error) {
30 switch msg := msg.(type) {
31 case MessageTauth:
32 qid, err := session.Auth(ctx, msg.Afid, msg.Uname, msg.Aname)
33 if err != nil {
34 return nil, err
35 }
37 return MessageRauth{Qid: qid}, nil
38 case MessageTattach:
39 qid, err := session.Attach(ctx, msg.Fid, msg.Afid, msg.Uname, msg.Aname)
40 if err != nil {
41 return nil, err
42 }
44 return MessageRattach{
45 Qid: qid,
46 }, nil
47 case MessageTwalk:
48 // TODO(stevvooe): This is one of the places where we need to manage
49 // fid allocation lifecycle. We need to reserve the fid, then, if this
50 // call succeeds, we should alloc the fid for future uses. Also need
51 // to interact correctly with concurrent clunk and the flush of this
52 // walk message.
53 qids, err := session.Walk(ctx, msg.Fid, msg.Newfid, msg.Wnames...)
54 if err != nil {
55 return nil, err
56 }
58 return MessageRwalk{
59 Qids: qids,
60 }, nil
61 case MessageTopen:
62 qid, iounit, err := session.Open(ctx, msg.Fid, msg.Mode)
63 if err != nil {
64 return nil, err
65 }
67 return MessageRopen{
68 Qid: qid,
69 IOUnit: iounit,
70 }, nil
71 case MessageTcreate:
72 qid, iounit, err := session.Create(ctx, msg.Fid, msg.Name, msg.Perm, msg.Mode)
73 if err != nil {
74 return nil, err
75 }
77 return MessageRcreate{
78 Qid: qid,
79 IOUnit: iounit,
80 }, nil
81 case MessageTread:
82 p := make([]byte, int(msg.Count))
83 n, err := session.Read(ctx, msg.Fid, p, int64(msg.Offset))
84 if err != nil {
85 return nil, err
86 }
88 return MessageRread{
89 Data: p[:n],
90 }, nil
91 case MessageTwrite:
92 n, err := session.Write(ctx, msg.Fid, msg.Data, int64(msg.Offset))
93 if err != nil {
94 return nil, err
95 }
97 return MessageRwrite{
98 Count: uint32(n),
99 }, nil
100 case MessageTclunk:
101 // TODO(stevvooe): Manage the clunking of file descriptors based on
102 // walk and attach call progression.
103 if err := session.Clunk(ctx, msg.Fid); err != nil {
104 return nil, err
107 return MessageRclunk{}, nil
108 case MessageTremove:
109 if err := session.Remove(ctx, msg.Fid); err != nil {
110 return nil, err
113 return MessageRremove{}, nil
114 case MessageTstat:
115 dir, err := session.Stat(ctx, msg.Fid)
116 if err != nil {
117 return nil, err
120 return MessageRstat{
121 Stat: dir,
122 }, nil
123 case MessageTwstat:
124 if err := session.WStat(ctx, msg.Fid, msg.Stat); err != nil {
125 return nil, err
128 return MessageRwstat{}, nil
129 default:
130 return nil, ErrUnknownMsg
132 })