55 "bytes"
66 "fmt"
77 "io"
8+ "io/ioutil"
89 "net/http"
910 "os"
1011 "path/filepath"
@@ -79,12 +80,11 @@ func (u *Update) isSupported() bool {
7980 return ok
8081}
8182
82- func (u * Update ) getFilepath () string {
83+ func (u * Update ) GetFilepath () string {
8384 return basedir + "/" + u .Name + "_" + u .Version + "_" + u .System .Arch + u .System .OS
8485}
8586
86- func (u * Update ) GetReader () (io.ReadCloser , error ) {
87- filepath := u .getFilepath ()
87+ func (u * Update ) GetReader (filepath string ) (io.ReadCloser , error ) {
8888 fd , err := os .Open (filepath )
8989 if err != nil {
9090 return nil , errors .Wrap (errBinaryNotFound , filepath )
@@ -143,7 +143,8 @@ func (svc *Service) UpdateHandler(ginCtx *gin.Context) {
143143 ginCtx .String (http .StatusNotModified , "" )
144144 return
145145 }
146- rc , err := update .GetReader ()
146+ fpath := update .GetFilepath ()
147+ rc , err := update .GetReader (fpath )
147148 if err != nil {
148149 ginCtx .AbortWithError (http .StatusInternalServerError , err ) // TODO: AbortWithError creates StackTraces, we want to have 4xx and an error log
149150 }
@@ -156,6 +157,7 @@ func (svc *Service) UpdateHandler(ginCtx *gin.Context) {
156157}
157158
158159// PatchUpdateHandler handles /patch-update/:name endpoint
160+ // TODO: use file cache to read and store binarydiff
159161func (svc * Service ) PatchUpdateHandler (ginCtx * gin.Context ) {
160162 newUpdate := newUpdateFromCtx (ginCtx )
161163 latestVersion := newUpdate .GetLatestVersion ()
@@ -167,14 +169,16 @@ func (svc *Service) PatchUpdateHandler(ginCtx *gin.Context) {
167169 oldUpdate := newUpdate .Clone ()
168170
169171 newUpdate .Version = latestVersion
170- rcNew , err := newUpdate .GetReader ()
172+ fpath := newUpdate .GetFilepath ()
173+ rcNew , err := newUpdate .GetReader (fpath )
171174 if err != nil {
172175 ginCtx .AbortWithError (http .StatusInternalServerError , err ) // TODO: AbortWithError creates StackTraces, we want to have 4xx and an error log
173176 }
174177 defer rcNew .Close ()
175178
176179 glog .Infof ("old: %v, new: %v" , oldUpdate , newUpdate )
177- rcOld , err := oldUpdate .GetReader ()
180+ fpath = oldUpdate .GetFilepath ()
181+ rcOld , err := oldUpdate .GetReader (fpath )
178182 if err != nil {
179183 ginCtx .AbortWithError (http .StatusInternalServerError , err ) // TODO: AbortWithError creates StackTraces, we want to have 4xx and an error log
180184 }
@@ -188,18 +192,107 @@ func (svc *Service) PatchUpdateHandler(ginCtx *gin.Context) {
188192 ginCtx .AbortWithError (http .StatusInternalServerError , fmt .Errorf ("failed to create a binary patch for %s: %v" , newUpdate .Name , err ))
189193 }
190194 rw .Flush ()
195+
191196 n , err := io .Copy (ginCtx .Writer , rw )
192197 if err != nil {
193198 ginCtx .AbortWithError (http .StatusInternalServerError , fmt .Errorf ("failed to copy %s to client: %v" , newUpdate .Name , err ))
194199 }
195-
196200 glog .Infof ("Copied %d bytes to client to patch %s" , n , newUpdate )
197201
198202}
199203
200204// SignedUpdateHandler handles /signed-update/:name endpoint
201205func (svc * Service ) SignedUpdateHandler (ginCtx * gin.Context ) {
202- ginCtx .AbortWithError (http .StatusInternalServerError , fmt .Errorf ("not implemented" ))
206+ newUpdate := newUpdateFromCtx (ginCtx )
207+ latestVersion := newUpdate .GetLatestVersion ()
208+ glog .V (2 ).Infof ("client has version %s, we have latest version %s" , newUpdate .Version , latestVersion )
209+ if newUpdate .Version == latestVersion {
210+ ginCtx .String (http .StatusNotModified , "" )
211+ return
212+ }
213+
214+ newUpdate .Version = latestVersion
215+ fpath := newUpdate .GetFilepath ()
216+
217+ binPatch , err := ioutil .ReadFile (fpath )
218+ if err != nil {
219+ ginCtx .AbortWithError (http .StatusInternalServerError , err ) // TODO: AbortWithError creates StackTraces, we want to have 4xx and an error log
220+ }
221+ signature , err := ioutil .ReadFile (fpath + ".signature" )
222+ if err != nil {
223+ ginCtx .AbortWithError (http .StatusInternalServerError , err ) // TODO: AbortWithError creates StackTraces, we want to have 4xx and an error log
224+ }
225+ digest , err := ioutil .ReadFile (fpath + ".sha256" )
226+ if err != nil {
227+ ginCtx .AbortWithError (http .StatusInternalServerError , err ) // TODO: AbortWithError creates StackTraces, we want to have 4xx and an error log
228+ }
229+
230+ ginCtx .JSON (http .StatusOK , gin.H {
231+ "patch" : binPatch ,
232+ "signature" : signature ,
233+ "sha256" : digest ,
234+ })
235+ glog .Infof ("Copied %d bytes to client to update %s" , len (binPatch ), newUpdate )
236+ }
237+
238+ // SignedPatchUpdateHandler handles /signed-patch-update/:name endpoint
239+ func (svc * Service ) SignedPatchUpdateHandler (ginCtx * gin.Context ) {
240+ newUpdate := newUpdateFromCtx (ginCtx )
241+ latestVersion := newUpdate .GetLatestVersion ()
242+ glog .V (2 ).Infof ("client has version %s, we have latest version %s" , newUpdate .Version , latestVersion )
243+ if newUpdate .Version == latestVersion {
244+ ginCtx .String (http .StatusNotModified , "" )
245+ return
246+ }
247+ oldUpdate := newUpdate .Clone ()
248+
249+ newUpdate .Version = latestVersion
250+ fpath := newUpdate .GetFilepath ()
251+ rcNew , err := newUpdate .GetReader (fpath )
252+ if err != nil {
253+ ginCtx .AbortWithError (http .StatusInternalServerError , err ) // TODO: AbortWithError creates StackTraces, we want to have 4xx and an error log
254+ }
255+ defer rcNew .Close ()
256+
257+ glog .Infof ("old: %v, new: %v" , oldUpdate , newUpdate )
258+ oldFpath := oldUpdate .GetFilepath ()
259+ rcOld , err := oldUpdate .GetReader (oldFpath )
260+ if err != nil {
261+ ginCtx .AbortWithError (http .StatusInternalServerError , err ) // TODO: AbortWithError creates StackTraces, we want to have 4xx and an error log
262+ }
263+ defer rcOld .Close ()
264+
265+ buf := bytes .NewBuffer (nil )
266+ rw := bufio .NewReadWriter (bufio .NewReader (buf ), bufio .NewWriter (buf ))
267+
268+ err = binarydist .Diff (rcOld , rcNew , rw )
269+ if err != nil {
270+ ginCtx .AbortWithError (http .StatusInternalServerError , fmt .Errorf ("failed to create a binary patch for %s: %v" , newUpdate .Name , err ))
271+ }
272+ rw .Flush ()
273+
274+ binPatch , err := ioutil .ReadAll (rw )
275+ if err != nil {
276+ ginCtx .AbortWithError (http .StatusInternalServerError , err ) // TODO: AbortWithError creates StackTraces, we want to have 4xx and an error log
277+ }
278+
279+ signature , err := ioutil .ReadFile (fpath + ".signature" )
280+ if err != nil {
281+ ginCtx .AbortWithError (http .StatusInternalServerError , err ) // TODO: AbortWithError creates StackTraces, we want to have 4xx and an error log
282+ }
283+
284+ digest , err := ioutil .ReadFile (fpath + ".sha256" )
285+ if err != nil {
286+ ginCtx .AbortWithError (http .StatusInternalServerError , err ) // TODO: AbortWithError creates StackTraces, we want to have 4xx and an error log
287+ }
288+
289+ ginCtx .JSON (http .StatusOK , gin.H {
290+ "patch" : binPatch ,
291+ "signature" : signature ,
292+ "sha256" : digest ,
293+ })
294+
295+ glog .Infof ("Copied %d bytes patch to client to patch %s" , len (binPatch ), newUpdate )
203296}
204297
205298// RootHandler handles / endpoint
0 commit comments