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