Blob


1 package p9p
3 import "golang.org/x/net/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 func (fn HandlerFunc) Handle(ctx context.Context, msg Message) (Message, error) {
21 return fn(ctx, msg)
22 }
24 // Dispatch returns a handler that dispatches messages to the target session.
25 // No concurrency is managed by the returned handler. It simply turns messages
26 // into function calls on the session.
27 func Dispatch(session Session) Handler {
28 return HandlerFunc(func(ctx context.Context, msg Message) (Message, error) {
29 switch msg := msg.(type) {
30 case MessageTauth:
31 qid, err := session.Auth(ctx, msg.Afid, msg.Uname, msg.Aname)
32 if err != nil {
33 return nil, err
34 }
36 return MessageRauth{Qid: qid}, nil
37 case MessageTattach:
38 qid, err := session.Attach(ctx, msg.Fid, msg.Afid, msg.Uname, msg.Aname)
39 if err != nil {
40 return nil, err
41 }
43 return MessageRattach{
44 Qid: qid,
45 }, nil
46 case MessageTwalk:
47 // TODO(stevvooe): This is one of the places where we need to manage
48 // fid allocation lifecycle. We need to reserve the fid, then, if this
49 // call succeeds, we should alloc the fid for future uses. Also need
50 // to interact correctly with concurrent clunk and the flush of this
51 // walk message.
52 qids, err := session.Walk(ctx, msg.Fid, msg.Newfid, msg.Wnames...)
53 if err != nil {
54 return nil, err
55 }
57 return MessageRwalk{
58 Qids: qids,
59 }, nil
60 case MessageTopen:
61 qid, iounit, err := session.Open(ctx, msg.Fid, msg.Mode)
62 if err != nil {
63 return nil, err
64 }
66 return MessageRopen{
67 Qid: qid,
68 IOUnit: iounit,
69 }, nil
70 case MessageTcreate:
71 qid, iounit, err := session.Create(ctx, msg.Fid, msg.Name, msg.Perm, msg.Mode)
72 if err != nil {
73 return nil, err
74 }
76 return MessageRcreate{
77 Qid: qid,
78 IOUnit: iounit,
79 }, nil
80 case MessageTread:
81 p := make([]byte, int(msg.Count))
82 n, err := session.Read(ctx, msg.Fid, p, int64(msg.Offset))
83 if err != nil {
84 return nil, err
85 }
87 return MessageRread{
88 Data: p[:n],
89 }, nil
90 case MessageTwrite:
91 n, err := session.Write(ctx, msg.Fid, msg.Data, int64(msg.Offset))
92 if err != nil {
93 return nil, err
94 }
96 return MessageRwrite{
97 Count: uint32(n),
98 }, nil
99 case MessageTclunk:
100 // TODO(stevvooe): Manage the clunking of file descriptors based on
101 // walk and attach call progression.
102 if err := session.Clunk(ctx, msg.Fid); err != nil {
103 return nil, err
106 return MessageRclunk{}, nil
107 case MessageTremove:
108 if err := session.Remove(ctx, msg.Fid); err != nil {
109 return nil, err
112 return MessageRremove{}, nil
113 case MessageTstat:
114 dir, err := session.Stat(ctx, msg.Fid)
115 if err != nil {
116 return nil, err
119 return MessageRstat{
120 Stat: dir,
121 }, nil
122 case MessageTwstat:
123 if err := session.WStat(ctx, msg.Fid, msg.Stat); err != nil {
124 return nil, err
127 return MessageRwstat{}, nil
128 default:
129 return nil, ErrUnknownMsg
131 })