initialise repo
[debian/orchestra.git] / src / orchestra / marshal.go
1 /* marshal.go
2  *
3  * Common wire marshalling code.
4 */
5
6 package orchestra;
7
8 import (
9         "os"
10         "goprotobuf.googlecode.com/hg/proto"
11 )
12
13 var (
14         ErrUnknownType = os.NewError("Unknown Type in Encode request")
15         ErrObjectTooLarge = os.NewError("Encoded Object exceeds maximum encoding size")
16 )
17
18 /* ugh ugh ugh.  As much as I love protocol buffers, not having maps
19  * as a native type is a PAIN IN THE ASS.
20  *
21  * Here's some common code to convert my K/V format in protocol
22  * buffers to and from native Go structures.
23 */
24 func MapFromProtoJobParameters(parray []*ProtoJobParameter) (mapparam map[string]string) {
25         mapparam = make(map[string]string)
26
27         for p := range parray {
28                 mapparam[*(parray[p].Key)] = *(parray[p].Value)
29         }
30
31         return mapparam
32 }
33
34 func ProtoJobParametersFromMap(mapparam map[string]string) (parray []*ProtoJobParameter) {
35         parray = make([]*ProtoJobParameter, len(mapparam))
36         i := 0
37         for k,v := range mapparam {
38                 arg := new(ProtoJobParameter)
39                 arg.Key = proto.String(k)
40                 arg.Value = proto.String(v)
41                 parray[i] = arg
42                 i++
43         }
44
45         return parray
46 }
47
48
49
50 func (p *WirePkt) Decode() (obj interface{}, err os.Error) {
51         switch (p.Type) {
52         case TypeNop:
53                 if (p.Length != 0) {
54                         /* throw error later... */
55                         return nil, ErrMalformedMessage;
56                 }
57                 return nil, nil
58         case TypeIdentifyClient:
59                 ic := new(IdentifyClient)
60                 err := proto.Unmarshal(p.Payload[0:p.Length], ic)
61                 if err != nil {
62                         return nil, err
63                 }
64                 return ic, nil
65         case TypeReadyForTask:
66                 if (p.Length != 0) {
67                         /* throw error later... */
68                         return nil, ErrMalformedMessage;
69                 }
70                 return nil, nil
71         case TypeTaskRequest:
72                 tr := new(ProtoTaskRequest)
73                 err := proto.Unmarshal(p.Payload[0:p.Length], tr)
74                 if err != nil {
75                         return nil, err
76                 }
77                 return tr, nil
78         case TypeTaskResponse:
79                 tr := new(ProtoTaskResponse)
80                 err := proto.Unmarshal(p.Payload[0:p.Length], tr)
81                 if err != nil {
82                         return nil, err
83                 }
84                 return tr, nil
85         case TypeAcknowledgement:
86                 tr := new(ProtoAcknowledgement)
87                 err := proto.Unmarshal(p.Payload[0:p.Length], tr)
88                 if err != nil {
89                         return nil, err
90                 }
91                 return tr, nil
92         }
93         return nil, ErrUnknownMessage
94 }
95
96 func Encode(obj interface{}) (p *WirePkt, err os.Error) {
97         p = new(WirePkt)
98         switch obj.(type) {
99         case *IdentifyClient:
100                 p.Type = TypeIdentifyClient
101         case *ProtoTaskRequest:
102                 p.Type = TypeTaskRequest
103         case *ProtoTaskResponse:
104                 p.Type = TypeTaskResponse
105         case *ProtoAcknowledgement:
106                 p.Type = TypeAcknowledgement
107         default:
108                 Warn("Encoding unknown type!")
109                 return nil, ErrUnknownType
110         }
111         p.Payload, err = proto.Marshal(obj)
112         if err != nil {
113                 return nil, err
114         }
115         if len(p.Payload) >= 0x10000 {
116                 return nil, ErrObjectTooLarge
117         }
118         p.Length = uint16(len(p.Payload))
119
120         return p, nil   
121 }
122
123
124 func MakeNop() (p *WirePkt) {
125         p = new(WirePkt)
126         p.Length = 0
127         p.Type = TypeNop
128         p.Payload = nil
129
130         return p
131 }
132
133 func MakeIdentifyClient(hostname string) (p *WirePkt) {
134         s := new(IdentifyClient)
135         s.Hostname = proto.String(hostname)
136
137         p, _ = Encode(s)
138         
139         return p
140 }
141
142 func MakeReadyForTask() (p *WirePkt){
143         p = new(WirePkt)
144         p.Type = TypeReadyForTask
145         p.Length = 0
146         p.Payload = nil
147
148         return p
149 }
150
151 /* We use the failure code for negative acknowledgements */
152 func MakeNack(id uint64) (p *WirePkt) {
153         a := new(ProtoAcknowledgement)
154         a.Id = proto.Uint64(id)
155         a.Response = new(ProtoAcknowledgement_AckType)
156         *(a.Response) = ProtoAcknowledgement_ACK_ERROR
157
158         p, _ = Encode(a)
159
160         return p
161 }
162
163 // Construct a positive ACK for transmission
164 func MakeAck(id uint64) (p *WirePkt) {
165         a := new(ProtoAcknowledgement)
166         a.Id = proto.Uint64(id)
167         a.Response = new(ProtoAcknowledgement_AckType)
168         *(a.Response) = ProtoAcknowledgement_ACK_OK
169
170         p, _ = Encode(a)
171
172         return p
173 }