2013-12-15 11:43:31 +01:00
|
|
|
package protocol
|
|
|
|
|
|
|
|
import "io"
|
|
|
|
|
|
|
|
type request struct {
|
|
|
|
name string
|
2014-01-09 16:35:49 +01:00
|
|
|
offset int64
|
2013-12-15 11:43:31 +01:00
|
|
|
size uint32
|
|
|
|
hash []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
type header struct {
|
|
|
|
version int
|
|
|
|
msgID int
|
|
|
|
msgType int
|
|
|
|
}
|
|
|
|
|
|
|
|
func encodeHeader(h header) uint32 {
|
|
|
|
return uint32(h.version&0xf)<<28 +
|
|
|
|
uint32(h.msgID&0xfff)<<16 +
|
|
|
|
uint32(h.msgType&0xff)<<8
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodeHeader(u uint32) header {
|
|
|
|
return header{
|
|
|
|
version: int(u>>28) & 0xf,
|
|
|
|
msgID: int(u>>16) & 0xfff,
|
|
|
|
msgType: int(u>>8) & 0xff,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *marshalWriter) writeHeader(h header) {
|
|
|
|
w.writeUint32(encodeHeader(h))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *marshalWriter) writeIndex(idx []FileInfo) {
|
|
|
|
w.writeUint32(uint32(len(idx)))
|
|
|
|
for _, f := range idx {
|
|
|
|
w.writeString(f.Name)
|
|
|
|
w.writeUint32(f.Flags)
|
|
|
|
w.writeUint64(uint64(f.Modified))
|
2014-01-07 22:44:21 +01:00
|
|
|
w.writeUint32(f.Version)
|
2013-12-15 11:43:31 +01:00
|
|
|
w.writeUint32(uint32(len(f.Blocks)))
|
|
|
|
for _, b := range f.Blocks {
|
2014-01-09 16:35:49 +01:00
|
|
|
w.writeUint32(b.Size)
|
2013-12-15 11:43:31 +01:00
|
|
|
w.writeBytes(b.Hash)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func WriteIndex(w io.Writer, idx []FileInfo) (int, error) {
|
2013-12-30 02:33:57 +01:00
|
|
|
mw := marshalWriter{w: w}
|
2013-12-15 11:43:31 +01:00
|
|
|
mw.writeIndex(idx)
|
2013-12-30 15:53:54 +01:00
|
|
|
return int(mw.getTot()), mw.err
|
2013-12-15 11:43:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (w *marshalWriter) writeRequest(r request) {
|
|
|
|
w.writeString(r.name)
|
2014-01-09 16:35:49 +01:00
|
|
|
w.writeUint64(uint64(r.offset))
|
2013-12-15 11:43:31 +01:00
|
|
|
w.writeUint32(r.size)
|
|
|
|
w.writeBytes(r.hash)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (w *marshalWriter) writeResponse(data []byte) {
|
|
|
|
w.writeBytes(data)
|
|
|
|
}
|
|
|
|
|
2014-01-23 13:12:45 +01:00
|
|
|
func (w *marshalWriter) writeOptions(opts map[string]string) {
|
|
|
|
w.writeUint32(uint32(len(opts)))
|
|
|
|
for k, v := range opts {
|
|
|
|
w.writeString(k)
|
|
|
|
w.writeString(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-15 11:43:31 +01:00
|
|
|
func (r *marshalReader) readHeader() header {
|
|
|
|
return decodeHeader(r.readUint32())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *marshalReader) readIndex() []FileInfo {
|
2013-12-15 13:12:32 +01:00
|
|
|
var files []FileInfo
|
2013-12-15 11:43:31 +01:00
|
|
|
nfiles := r.readUint32()
|
2013-12-15 13:12:32 +01:00
|
|
|
if nfiles > 0 {
|
|
|
|
files = make([]FileInfo, nfiles)
|
|
|
|
for i := range files {
|
|
|
|
files[i].Name = r.readString()
|
|
|
|
files[i].Flags = r.readUint32()
|
|
|
|
files[i].Modified = int64(r.readUint64())
|
2014-01-07 22:44:21 +01:00
|
|
|
files[i].Version = r.readUint32()
|
2013-12-15 13:12:32 +01:00
|
|
|
nblocks := r.readUint32()
|
|
|
|
blocks := make([]BlockInfo, nblocks)
|
|
|
|
for j := range blocks {
|
2014-01-09 16:35:49 +01:00
|
|
|
blocks[j].Size = r.readUint32()
|
2013-12-15 13:12:32 +01:00
|
|
|
blocks[j].Hash = r.readBytes()
|
|
|
|
}
|
|
|
|
files[i].Blocks = blocks
|
2013-12-15 11:43:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return files
|
|
|
|
}
|
|
|
|
|
|
|
|
func ReadIndex(r io.Reader) ([]FileInfo, error) {
|
2013-12-30 02:33:57 +01:00
|
|
|
mr := marshalReader{r: r}
|
2013-12-15 11:43:31 +01:00
|
|
|
idx := mr.readIndex()
|
|
|
|
return idx, mr.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *marshalReader) readRequest() request {
|
|
|
|
var req request
|
|
|
|
req.name = r.readString()
|
2014-01-09 16:35:49 +01:00
|
|
|
req.offset = int64(r.readUint64())
|
2013-12-15 11:43:31 +01:00
|
|
|
req.size = r.readUint32()
|
|
|
|
req.hash = r.readBytes()
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *marshalReader) readResponse() []byte {
|
|
|
|
return r.readBytes()
|
|
|
|
}
|
2014-01-23 13:12:45 +01:00
|
|
|
|
|
|
|
func (r *marshalReader) readOptions() map[string]string {
|
|
|
|
n := r.readUint32()
|
|
|
|
opts := make(map[string]string, n)
|
|
|
|
for i := 0; i < int(n); i++ {
|
|
|
|
k := r.readString()
|
|
|
|
v := r.readString()
|
|
|
|
opts[k] = v
|
|
|
|
}
|
|
|
|
return opts
|
|
|
|
}
|