Blob


1 package p9pnew
3 import (
4 "fmt"
6 "golang.org/x/net/context"
7 )
9 type handler interface {
10 handle(ctx context.Context, req *Fcall) (*Fcall, error)
11 }
13 // dispatcher routes fcalls to a Session.
14 type dispatcher struct {
15 session Session
16 }
18 // handle responds to an fcall using the session. An error is only returned if
19 // the handler cannot proceed. All session errors are returned as Rerror.
20 func (d *dispatcher) handle(ctx context.Context, req *Fcall) (*Fcall, error) {
21 var resp *Fcall
22 switch req.Type {
23 case Tauth:
24 reqmsg, ok := req.Message.(MessageTauth)
25 if !ok {
26 return nil, fmt.Errorf("incorrect message for type: %v message=%v", req, req.Message)
27 }
29 qid, err := d.session.Auth(ctx, reqmsg.Afid, reqmsg.Uname, reqmsg.Aname)
30 if err != nil {
31 return nil, err
32 }
34 resp = newFcall(MessageRauth{Qid: qid})
35 case Tattach:
36 reqmsg, ok := req.Message.(*MessageTattach)
37 if !ok {
38 return nil, fmt.Errorf("bad message: %v message=%#v", req, req.Message)
39 }
41 qid, err := d.session.Attach(ctx, reqmsg.Fid, reqmsg.Afid, reqmsg.Uname, reqmsg.Aname)
42 if err != nil {
43 return nil, err
44 }
46 resp = newFcall(MessageRattach{
47 Qid: qid,
48 })
49 case Twalk:
50 reqmsg, ok := req.Message.(*MessageTwalk)
51 if !ok {
52 return nil, fmt.Errorf("bad message: %v message=%#v", req, req.Message)
53 }
55 // TODO(stevvooe): This is one of the places where we need to manage
56 // fid allocation lifecycle. We need to reserve the fid, then, if this
57 // call succeeds, we should alloc the fid for future uses. Also need
58 // to interact correctly with concurrent clunk and the flush of this
59 // walk message.
60 qids, err := d.session.Walk(ctx, reqmsg.Fid, reqmsg.Newfid, reqmsg.Wnames...)
61 if err != nil {
62 return nil, err
63 }
65 resp = newFcall(&MessageRwalk{
66 Qids: qids,
67 })
68 case Topen:
69 reqmsg, ok := req.Message.(*MessageTopen)
70 if !ok {
71 return nil, fmt.Errorf("bad message: %v message=%v", req, req.Message)
72 }
74 qid, iounit, err := d.session.Open(ctx, reqmsg.Fid, reqmsg.Mode)
75 if err != nil {
76 return nil, err
77 }
79 resp = newFcall(&MessageRopen{
80 Qid: qid,
81 IOUnit: iounit,
82 })
83 case Tcreate:
84 reqmsg, ok := req.Message.(*MessageTcreate)
85 if !ok {
86 return nil, fmt.Errorf("bad message: %v message=%v", req, req.Message)
87 }
89 qid, iounit, err := d.session.Create(ctx, reqmsg.Fid, reqmsg.Name, reqmsg.Perm, uint32(reqmsg.Mode))
90 if err != nil {
91 return nil, err
92 }
94 resp = newFcall(&MessageRcreate{
95 Qid: qid,
96 IOUnit: iounit,
97 })
99 case Tread:
100 reqmsg, ok := req.Message.(*MessageTread)
101 if !ok {
102 return nil, fmt.Errorf("bad message: %v message=%v", req, req.Message)
105 p := make([]byte, int(reqmsg.Count))
106 n, err := d.session.Read(ctx, reqmsg.Fid, p, int64(reqmsg.Offset))
107 if err != nil {
108 return nil, err
111 resp = newFcall(&MessageRread{
112 Data: p[:n],
113 })
114 case Twrite:
115 reqmsg, ok := req.Message.(*MessageTwrite)
116 if !ok {
117 return nil, fmt.Errorf("bad message: %v message=%v", req, req.Message)
120 n, err := d.session.Write(ctx, reqmsg.Fid, reqmsg.Data, int64(reqmsg.Offset))
121 if err != nil {
122 return nil, err
125 resp = newFcall(&MessageRwrite{
126 Count: uint32(n),
127 })
128 case Tclunk:
129 reqmsg, ok := req.Message.(*MessageTclunk)
130 if !ok {
131 return nil, fmt.Errorf("bad message: %v message=%v", req, req.Message)
134 // TODO(stevvooe): Manage the clunking of file descriptors based on
135 // walk and attach call progression.
136 if err := d.session.Clunk(ctx, reqmsg.Fid); err != nil {
137 return nil, err
140 resp = newFcall(&MessageRclunk{})
141 case Tremove:
142 reqmsg, ok := req.Message.(*MessageTremove)
143 if !ok {
144 return nil, fmt.Errorf("bad message: %v message=%v", req, req.Message)
147 if err := d.session.Remove(ctx, reqmsg.Fid); err != nil {
148 return nil, err
151 resp = newFcall(&MessageRremove{})
152 case Tstat:
153 reqmsg, ok := req.Message.(*MessageTstat)
154 if !ok {
155 return nil, fmt.Errorf("bad message: %v message=%v", req, req.Message)
158 dir, err := d.session.Stat(ctx, reqmsg.Fid)
159 if err != nil {
160 return nil, err
163 resp = newFcall(&MessageRstat{
164 Stat: dir,
165 })
166 case Twstat:
167 panic("not implemented")
168 default:
169 return nil, ErrUnknownMsg
172 return resp, nil