-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathio.go
More file actions
142 lines (127 loc) · 3.41 KB
/
Copy pathio.go
File metadata and controls
142 lines (127 loc) · 3.41 KB
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
134
135
136
137
138
139
140
141
142
/*
* Licensed Materials - Property of tenxcloud.com
* (C) Copyright 2019 TenxCloud. All Rights Reserved.
* 2019-03-20 @author lizhen
*/
package serviced
import (
"context"
"reflect"
)
type IO interface {
In() (rawMessage <-chan *Message)
Out() (rawMessage chan<- *Message)
}
type Server interface {
Start(ctx context.Context) error
}
type server struct {
Queue InvocationQueue
Invocations Invocations
Kernel Kernel
Serializer Serializer
IO IO
}
func (s server) Start(ctx context.Context) error {
defer s.Queue.Close()
for {
select {
case message := <-s.IO.In():
if err := s.dispatch(message); err != nil {
return err
}
case message := <-s.Queue.Out():
s.IO.Out() <- message
case <-ctx.Done():
return ctx.Err()
}
}
}
func (s server) dispatch(message *Message) (err error) {
if message.RequestID == "" {
err = ErrInvalidMessage
return
}
if message.IsResponse {
err = s.handleResponse(message)
} else {
err = s.handleRequest(message)
}
return
}
func (s server) handleDebug(debugger Debugger, message *Message) (response *Message, err error) {
var arguments []interface{}
if arguments, err = objectToInterface(s.Kernel, s.Serializer, message.Arguments); err != nil {
return
}
returnValues := debugger.Call(message.Method, arguments)
response = new(Message)
response.RequestID = message.RequestID
response.IsResponse = true
response.ReturnValues, err = interfaceToObject(s.Serializer, returnValues)
return
}
func (s server) handleRequest(message *Message) (err error) {
var service interface{}
if service, err = s.Kernel.ResolveService(message.Service); err != nil {
return
}
var response *Message
if d, ok := service.(Debugger); ok {
if response, err = s.handleDebug(d, message); err != nil {
return
}
} else {
if response, err = s.call(service, message); err != nil {
return
}
}
s.Queue.In() <- response
return
}
func (s server) prepareArguments(service reflect.Value, message *Message) (arguments []reflect.Value, err error) {
count := len(message.Arguments)
var a []reflect.Value
if a, err = objectToValue(s.Kernel, s.Serializer, message.Arguments); err != nil {
return
}
arguments = make([]reflect.Value, 0, count+1)
arguments[0] = service
for i := 0; i < count; i++ {
arguments[i+1] = a[i]
}
return
}
func (s server) prepareReturnValues(returnValues []reflect.Value) (objects []object, err error) {
objects, err = valueToObject(s.Serializer, returnValues)
return
}
func (s server) prepareResponse(request *Message, returnValues []reflect.Value) (response *Message, err error) {
response = new(Message)
response.RequestID = request.RequestID
response.IsResponse = true
response.ReturnValues, err = s.prepareReturnValues(returnValues)
return
}
type Debugger interface {
Call(method string, arguments []interface{}) (returnValues []interface{})
}
func (s server) call(service interface{}, message *Message) (response *Message, err error) {
var arguments []reflect.Value
sv := reflect.ValueOf(service)
if arguments, err = s.prepareArguments(sv, message); err != nil {
return
}
returnValues := sv.MethodByName(message.Method).Call(arguments)
response, err = s.prepareResponse(message, returnValues)
return
}
func (s server) handleResponse(message *Message) (err error) {
var response chan<- *Message
if response, err = s.Invocations.Get(message.RequestID); err != nil {
return
}
defer close(response)
response <- message
return
}