manifest.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. // Copyright 2016 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package api
  17. import (
  18. "bytes"
  19. "encoding/json"
  20. "fmt"
  21. "sync"
  22. "github.com/ethereum/go-ethereum/common"
  23. "github.com/ethereum/go-ethereum/logger"
  24. "github.com/ethereum/go-ethereum/logger/glog"
  25. "github.com/ethereum/go-ethereum/swarm/storage"
  26. )
  27. const (
  28. manifestType = "application/bzz-manifest+json"
  29. )
  30. type manifestTrie struct {
  31. dpa *storage.DPA
  32. entries [257]*manifestTrieEntry // indexed by first character of path, entries[256] is the empty path entry
  33. hash storage.Key // if hash != nil, it is stored
  34. }
  35. type manifestJSON struct {
  36. Entries []*manifestTrieEntry `json:"entries"`
  37. }
  38. type manifestTrieEntry struct {
  39. Path string `json:"path"`
  40. Hash string `json:"hash"` // for manifest content type, empty until subtrie is evaluated
  41. ContentType string `json:"contentType"`
  42. Status int `json:"status"`
  43. subtrie *manifestTrie
  44. }
  45. func loadManifest(dpa *storage.DPA, hash storage.Key, quitC chan bool) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand
  46. glog.V(logger.Detail).Infof("manifest lookup key: '%v'.", hash.Log())
  47. // retrieve manifest via DPA
  48. manifestReader := dpa.Retrieve(hash)
  49. return readManifest(manifestReader, hash, dpa, quitC)
  50. }
  51. func readManifest(manifestReader storage.LazySectionReader, hash storage.Key, dpa *storage.DPA, quitC chan bool) (trie *manifestTrie, err error) { // non-recursive, subtrees are downloaded on-demand
  52. // TODO check size for oversized manifests
  53. size, err := manifestReader.Size(quitC)
  54. manifestData := make([]byte, size)
  55. read, err := manifestReader.Read(manifestData)
  56. if int64(read) < size {
  57. glog.V(logger.Detail).Infof("Manifest %v not found.", hash.Log())
  58. if err == nil {
  59. err = fmt.Errorf("Manifest retrieval cut short: read %v, expect %v", read, size)
  60. }
  61. return
  62. }
  63. glog.V(logger.Detail).Infof("Manifest %v retrieved", hash.Log())
  64. man := manifestJSON{}
  65. err = json.Unmarshal(manifestData, &man)
  66. if err != nil {
  67. err = fmt.Errorf("Manifest %v is malformed: %v", hash.Log(), err)
  68. glog.V(logger.Detail).Infof("%v", err)
  69. return
  70. }
  71. glog.V(logger.Detail).Infof("Manifest %v has %d entries.", hash.Log(), len(man.Entries))
  72. trie = &manifestTrie{
  73. dpa: dpa,
  74. }
  75. for _, entry := range man.Entries {
  76. trie.addEntry(entry, quitC)
  77. }
  78. return
  79. }
  80. func (self *manifestTrie) addEntry(entry *manifestTrieEntry, quitC chan bool) {
  81. self.hash = nil // trie modified, hash needs to be re-calculated on demand
  82. if len(entry.Path) == 0 {
  83. self.entries[256] = entry
  84. return
  85. }
  86. b := byte(entry.Path[0])
  87. if (self.entries[b] == nil) || (self.entries[b].Path == entry.Path) {
  88. self.entries[b] = entry
  89. return
  90. }
  91. oldentry := self.entries[b]
  92. cpl := 0
  93. for (len(entry.Path) > cpl) && (len(oldentry.Path) > cpl) && (entry.Path[cpl] == oldentry.Path[cpl]) {
  94. cpl++
  95. }
  96. if (oldentry.ContentType == manifestType) && (cpl == len(oldentry.Path)) {
  97. if self.loadSubTrie(oldentry, quitC) != nil {
  98. return
  99. }
  100. entry.Path = entry.Path[cpl:]
  101. oldentry.subtrie.addEntry(entry, quitC)
  102. oldentry.Hash = ""
  103. return
  104. }
  105. commonPrefix := entry.Path[:cpl]
  106. subtrie := &manifestTrie{
  107. dpa: self.dpa,
  108. }
  109. entry.Path = entry.Path[cpl:]
  110. oldentry.Path = oldentry.Path[cpl:]
  111. subtrie.addEntry(entry, quitC)
  112. subtrie.addEntry(oldentry, quitC)
  113. self.entries[b] = &manifestTrieEntry{
  114. Path: commonPrefix,
  115. Hash: "",
  116. ContentType: manifestType,
  117. subtrie: subtrie,
  118. }
  119. }
  120. func (self *manifestTrie) getCountLast() (cnt int, entry *manifestTrieEntry) {
  121. for _, e := range self.entries {
  122. if e != nil {
  123. cnt++
  124. entry = e
  125. }
  126. }
  127. return
  128. }
  129. func (self *manifestTrie) deleteEntry(path string, quitC chan bool) {
  130. self.hash = nil // trie modified, hash needs to be re-calculated on demand
  131. if len(path) == 0 {
  132. self.entries[256] = nil
  133. return
  134. }
  135. b := byte(path[0])
  136. entry := self.entries[b]
  137. if entry == nil {
  138. return
  139. }
  140. if entry.Path == path {
  141. self.entries[b] = nil
  142. return
  143. }
  144. epl := len(entry.Path)
  145. if (entry.ContentType == manifestType) && (len(path) >= epl) && (path[:epl] == entry.Path) {
  146. if self.loadSubTrie(entry, quitC) != nil {
  147. return
  148. }
  149. entry.subtrie.deleteEntry(path[epl:], quitC)
  150. entry.Hash = ""
  151. // remove subtree if it has less than 2 elements
  152. cnt, lastentry := entry.subtrie.getCountLast()
  153. if cnt < 2 {
  154. if lastentry != nil {
  155. lastentry.Path = entry.Path + lastentry.Path
  156. }
  157. self.entries[b] = lastentry
  158. }
  159. }
  160. }
  161. func (self *manifestTrie) recalcAndStore() error {
  162. if self.hash != nil {
  163. return nil
  164. }
  165. var buffer bytes.Buffer
  166. buffer.WriteString(`{"entries":[`)
  167. list := &manifestJSON{}
  168. for _, entry := range self.entries {
  169. if entry != nil {
  170. if entry.Hash == "" { // TODO: paralellize
  171. err := entry.subtrie.recalcAndStore()
  172. if err != nil {
  173. return err
  174. }
  175. entry.Hash = entry.subtrie.hash.String()
  176. }
  177. list.Entries = append(list.Entries, entry)
  178. }
  179. }
  180. manifest, err := json.Marshal(list)
  181. if err != nil {
  182. return err
  183. }
  184. sr := bytes.NewReader(manifest)
  185. wg := &sync.WaitGroup{}
  186. key, err2 := self.dpa.Store(sr, int64(len(manifest)), wg, nil)
  187. wg.Wait()
  188. self.hash = key
  189. return err2
  190. }
  191. func (self *manifestTrie) loadSubTrie(entry *manifestTrieEntry, quitC chan bool) (err error) {
  192. if entry.subtrie == nil {
  193. hash := common.Hex2Bytes(entry.Hash)
  194. entry.subtrie, err = loadManifest(self.dpa, hash, quitC)
  195. entry.Hash = "" // might not match, should be recalculated
  196. }
  197. return
  198. }
  199. func (self *manifestTrie) listWithPrefixInt(prefix, rp string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) error {
  200. plen := len(prefix)
  201. var start, stop int
  202. if plen == 0 {
  203. start = 0
  204. stop = 256
  205. } else {
  206. start = int(prefix[0])
  207. stop = start
  208. }
  209. for i := start; i <= stop; i++ {
  210. select {
  211. case <-quitC:
  212. return fmt.Errorf("aborted")
  213. default:
  214. }
  215. entry := self.entries[i]
  216. if entry != nil {
  217. epl := len(entry.Path)
  218. if entry.ContentType == manifestType {
  219. l := plen
  220. if epl < l {
  221. l = epl
  222. }
  223. if prefix[:l] == entry.Path[:l] {
  224. err := self.loadSubTrie(entry, quitC)
  225. if err != nil {
  226. return err
  227. }
  228. err = entry.subtrie.listWithPrefixInt(prefix[l:], rp+entry.Path[l:], quitC, cb)
  229. if err != nil {
  230. return err
  231. }
  232. }
  233. } else {
  234. if (epl >= plen) && (prefix == entry.Path[:plen]) {
  235. cb(entry, rp+entry.Path[plen:])
  236. }
  237. }
  238. }
  239. }
  240. return nil
  241. }
  242. func (self *manifestTrie) listWithPrefix(prefix string, quitC chan bool, cb func(entry *manifestTrieEntry, suffix string)) (err error) {
  243. return self.listWithPrefixInt(prefix, "", quitC, cb)
  244. }
  245. func (self *manifestTrie) findPrefixOf(path string, quitC chan bool) (entry *manifestTrieEntry, pos int) {
  246. glog.V(logger.Detail).Infof("findPrefixOf(%s)", path)
  247. if len(path) == 0 {
  248. return self.entries[256], 0
  249. }
  250. b := byte(path[0])
  251. entry = self.entries[b]
  252. if entry == nil {
  253. return self.entries[256], 0
  254. }
  255. epl := len(entry.Path)
  256. glog.V(logger.Detail).Infof("path = %v entry.Path = %v epl = %v", path, entry.Path, epl)
  257. if (len(path) >= epl) && (path[:epl] == entry.Path) {
  258. glog.V(logger.Detail).Infof("entry.ContentType = %v", entry.ContentType)
  259. if entry.ContentType == manifestType {
  260. if self.loadSubTrie(entry, quitC) != nil {
  261. return nil, 0
  262. }
  263. entry, pos = entry.subtrie.findPrefixOf(path[epl:], quitC)
  264. if entry != nil {
  265. pos += epl
  266. }
  267. } else {
  268. pos = epl
  269. }
  270. } else {
  271. entry = nil
  272. }
  273. return
  274. }
  275. // file system manifest always contains regularized paths
  276. // no leading or trailing slashes, only single slashes inside
  277. func RegularSlashes(path string) (res string) {
  278. for i := 0; i < len(path); i++ {
  279. if (path[i] != '/') || ((i > 0) && (path[i-1] != '/')) {
  280. res = res + path[i:i+1]
  281. }
  282. }
  283. if (len(res) > 0) && (res[len(res)-1] == '/') {
  284. res = res[:len(res)-1]
  285. }
  286. return
  287. }
  288. func (self *manifestTrie) getEntry(spath string) (entry *manifestTrieEntry, fullpath string) {
  289. path := RegularSlashes(spath)
  290. var pos int
  291. quitC := make(chan bool)
  292. entry, pos = self.findPrefixOf(path, quitC)
  293. return entry, path[:pos]
  294. }