-
Notifications
You must be signed in to change notification settings - Fork 66
/
http_test.go
174 lines (138 loc) · 3.94 KB
/
http_test.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package gosync
import (
"bytes"
"crypto/md5"
"fmt"
"net"
"net/http"
"time"
"github.com/Redundancy/go-sync/blocksources"
"github.com/Redundancy/go-sync/comparer"
"github.com/Redundancy/go-sync/filechecksum"
"github.com/Redundancy/go-sync/indexbuilder"
"github.com/Redundancy/go-sync/patcher"
)
// due to short example strings, use a very small block size
// using one this small in practice would increase your file transfer!
const BLOCK_SIZE = 4
// This is the "file" as described by the authoritive version
const REFERENCE = "The quick brown fox jumped over the lazy dog"
// This is what we have locally. Not too far off, but not correct.
const LOCAL_VERSION = "The qwik brown fox jumped 0v3r the lazy"
var content = bytes.NewReader([]byte(REFERENCE))
func handler(w http.ResponseWriter, req *http.Request) {
http.ServeContent(w, req, "", time.Now(), content)
}
// set up a http server locally that will respond predictably to ranged requests
func setupServer() <-chan int {
var PORT = 8000
s := http.NewServeMux()
s.HandleFunc("/content", handler)
portChan := make(chan int)
go func() {
var listener net.Listener
var err error
for {
PORT++
p := fmt.Sprintf(":%v", PORT)
listener, err = net.Listen("tcp", p)
if err == nil {
break
}
}
portChan <- PORT
http.Serve(listener, s)
}()
return portChan
}
// This is exceedingly similar to the module Example, but uses the http blocksource and a local http server
func Example_httpBlockSource() {
PORT := <-setupServer()
LOCAL_URL := fmt.Sprintf("http://localhost:%v/content", PORT)
generator := filechecksum.NewFileChecksumGenerator(BLOCK_SIZE)
_, referenceFileIndex, checksumLookup, err := indexbuilder.BuildIndexFromString(generator, REFERENCE)
if err != nil {
return
}
fileSize := int64(len([]byte(REFERENCE)))
// This would normally be saved in a file
blockCount := fileSize / BLOCK_SIZE
if fileSize%BLOCK_SIZE != 0 {
blockCount++
}
fs := &BasicSummary{
ChecksumIndex: referenceFileIndex,
ChecksumLookup: checksumLookup,
BlockCount: uint(blockCount),
BlockSize: uint(BLOCK_SIZE),
FileSize: fileSize,
}
/*
// Normally, this would be:
rsync, err := MakeRSync(
"toPatch.file",
"http://localhost/content",
"out.file",
fs,
)
*/
// Need to replace the output and the input
inputFile := bytes.NewReader([]byte(LOCAL_VERSION))
patchedFile := bytes.NewBuffer(nil)
resolver := blocksources.MakeFileSizedBlockResolver(
uint64(fs.GetBlockSize()),
fs.GetFileSize(),
)
rsync := &RSync{
Input: inputFile,
Output: patchedFile,
Source: blocksources.NewHttpBlockSource(
LOCAL_URL,
1,
resolver,
&filechecksum.HashVerifier{
Hash: md5.New(),
BlockSize: fs.GetBlockSize(),
BlockChecksumGetter: fs,
},
),
Summary: fs,
OnClose: nil,
}
err = rsync.Patch()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
err = rsync.Close()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Patched content: \"%v\"\n", patchedFile.String())
// Just for inspection
remoteReferenceSource := rsync.Source.(*blocksources.BlockSourceBase)
fmt.Printf("Downloaded Bytes: %v\n", remoteReferenceSource.ReadBytes())
// Output:
// Patched content: "The quick brown fox jumped over the lazy dog"
// Downloaded Bytes: 16
}
func ToPatcherFoundSpan(sl comparer.BlockSpanList, blockSize int64) []patcher.FoundBlockSpan {
result := make([]patcher.FoundBlockSpan, len(sl))
for i, v := range sl {
result[i].StartBlock = v.StartBlock
result[i].EndBlock = v.EndBlock
result[i].MatchOffset = v.ComparisonStartOffset
result[i].BlockSize = blockSize
}
return result
}
func ToPatcherMissingSpan(sl comparer.BlockSpanList, blockSize int64) []patcher.MissingBlockSpan {
result := make([]patcher.MissingBlockSpan, len(sl))
for i, v := range sl {
result[i].StartBlock = v.StartBlock
result[i].EndBlock = v.EndBlock
result[i].BlockSize = blockSize
}
return result
}