databaseRead.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. package lib
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "sort"
  6. )
  7. //topicPointer and textPointer should not be exported
  8. //mb move tweet reconstruction to dbRead from servers
  9. type Tweet struct {
  10. TopicPointer string
  11. TextPointer int
  12. Topics []string
  13. Text string
  14. RoundPosted int
  15. }
  16. var dbR = make(map[string][]Tweet)
  17. var archive = make(map[string][]Tweet)
  18. //has to be dividable by 32
  19. var minimumBlockSize int
  20. //needs to be dividable by roundsBeforUpdate
  21. var roundsBeforeArchiving = 12
  22. var bytesSaved float64
  23. var topicList []string
  24. var archiveTopicList []string
  25. func NewEntries(inputTweets []Tweet, whereTo int) {
  26. tmpdb := dbR
  27. if whereTo == 1 {
  28. tmpdb = archive
  29. }
  30. var position int = 0
  31. for _, tweet := range inputTweets {
  32. for index := range tweet.Topics {
  33. //fmt.Println("topic to put in", tweet.Topics[index])
  34. //new topic
  35. if _, ok := tmpdb[tweet.Topics[index]]; !ok {
  36. if whereTo == 0 {
  37. topicList = append(topicList, tweet.Topics[index])
  38. } else {
  39. archiveTopicList = append(archiveTopicList, tweet.Topics[index])
  40. }
  41. }
  42. //new tweet
  43. if index == 0 {
  44. position = len(tmpdb[tweet.Topics[0]])
  45. tmpdb[tweet.Topics[index]] = append(tmpdb[tweet.Topics[0]], tweet)
  46. } else {
  47. //known tweet
  48. //setting pointer for all other Topics
  49. if whereTo == 1 {
  50. bytesSaved += float64(len(tweet.Topics)) + float64(len(tweet.Text))
  51. }
  52. topic := tweet.Topics[index]
  53. var pointerTweet Tweet
  54. pointerTweet.TopicPointer = tweet.Topics[0]
  55. pointerTweet.TextPointer = position
  56. pointerTweet.Topics = nil
  57. pointerTweet.Text = ""
  58. tmpdb[topic] = append(tmpdb[topic], pointerTweet)
  59. }
  60. }
  61. }
  62. if whereTo == 0 {
  63. dbR = tmpdb
  64. } else {
  65. archive = tmpdb
  66. }
  67. }
  68. //todo! add round to pirquery only get tweets that have been posted from that round onward
  69. func GetTweets(pirQuery []byte, dataLength int, whereFrom int, pubKey [32]byte) []byte {
  70. //fmt.Println("query", pirQuery)
  71. //fmt.Println("dbR", dbR)
  72. tmpdb := dbR
  73. if whereFrom == 1 {
  74. tmpdb = archive
  75. }
  76. minimumBlockSize = dataLength * maxTweetAmount(whereFrom)
  77. var wantedTopics = getNamesForTopics(pirQuery, whereFrom)
  78. tweetsToReturn := make([][]Tweet, len(wantedTopics))
  79. for index, wantedTopic := range wantedTopics {
  80. for _, tweet := range tmpdb[wantedTopic] {
  81. //fmt.Println(tweet)
  82. //new Tweet
  83. if tweet.Text != "" {
  84. tweet.RoundPosted = 0
  85. tweetsToReturn[index] = append(tweetsToReturn[index], tweet)
  86. } else {
  87. //"copied" tweet
  88. //find tweet with pointers
  89. tweet = tmpdb[tweet.TopicPointer][tweet.TextPointer]
  90. tweet.RoundPosted = 0
  91. tweetsToReturn[index] = append(tweetsToReturn[index], tweet)
  92. }
  93. }
  94. }
  95. return tweetsToByteArray(tweetsToReturn, whereFrom, wantedTopics)
  96. }
  97. func maxTweetAmount(whereFrom int) int {
  98. tmpdb := dbR
  99. if whereFrom == 1 {
  100. tmpdb = archive
  101. }
  102. var max int = 0
  103. for i := range tmpdb {
  104. nrOfTweets := len(tmpdb[i])
  105. if nrOfTweets > max {
  106. max = nrOfTweets
  107. }
  108. }
  109. return max
  110. }
  111. func getNamesForTopics(wantedIndices []byte, whereFrom int) []string {
  112. var topicNames []string
  113. tmpTopicList := topicList
  114. if whereFrom == 1 {
  115. tmpTopicList = archiveTopicList
  116. }
  117. for index, element := range wantedIndices {
  118. if index == len(tmpTopicList) {
  119. break
  120. }
  121. if element == 1 {
  122. topicNames = append(topicNames, tmpTopicList[index])
  123. }
  124. }
  125. return topicNames
  126. }
  127. //transform struct to byte array for sending
  128. func tweetsToByteArray(tweetsToReturn [][]Tweet, whereFrom int, wantedTopics []string) []byte {
  129. tweetsAsBytes := make([]byte, minimumBlockSize)
  130. for _, block := range tweetsToReturn {
  131. var topicPadding []string
  132. var blockToAppend []byte
  133. for index, tweet := range block {
  134. for topicIndex, topic := range tweet.Topics {
  135. blockToAppend = append(blockToAppend, []byte(topic)...)
  136. blockToAppend = append(blockToAppend, ","...)
  137. //gets the topic used for padding
  138. if topicIndex > 0 && index < len(wantedTopics) && topic != wantedTopics[index] {
  139. topicPadding = append(topicPadding, topic)
  140. }
  141. }
  142. //replaces last "," with ";;" bc there is text following and not another topic
  143. blockToAppend = blockToAppend[:len(blockToAppend)-1]
  144. blockToAppend = append(blockToAppend, []byte(";;")[:]...)
  145. blockToAppend = append(blockToAppend, []byte(tweet.Text)...)
  146. blockToAppend = append(blockToAppend, []byte(";")[0])
  147. }
  148. //adds padding
  149. blockToAppend = append(blockToAppend, []byte(";;;")[:]...)
  150. remainingLength := minimumBlockSize - len(blockToAppend)
  151. //grouping using topic from recovered tweets
  152. index := len(topicPadding) - 1
  153. for index >= 0 && remainingLength > 0 && topicPadding[index] != "" {
  154. paddingTweet, err := getNextTweet(topicPadding[index], index, whereFrom)
  155. if err {
  156. break
  157. }
  158. if remainingLength < len(paddingTweet) {
  159. break
  160. }
  161. blockToAppend = append(blockToAppend, paddingTweet...)
  162. remainingLength -= len(paddingTweet)
  163. index--
  164. }
  165. padding := bytes.Repeat([]byte(";"), remainingLength)
  166. blockToAppend = append(blockToAppend, padding...)
  167. Xor(blockToAppend, tweetsAsBytes)
  168. //fmt.Println(tweetsAsBytes)
  169. }
  170. //fmt.Println("length Returned", len(tweetsAsBytes))
  171. return tweetsAsBytes
  172. }
  173. //gets the Tweet at index from wantedTopic for padding
  174. func getNextTweet(wantedTopic string, index, whereFrom int) ([]byte, bool) {
  175. tmpdb := dbR
  176. if whereFrom == 1 {
  177. tmpdb = archive
  178. }
  179. var tweetToReturn Tweet
  180. for tweetIndex, tweet := range tmpdb[wantedTopic] {
  181. if len(tmpdb[wantedTopic]) <= index {
  182. return nil, true
  183. } else if tweetIndex < index {
  184. continue
  185. } else if tweetIndex > index {
  186. break
  187. }
  188. //new Tweet
  189. if tweet.Text != "" {
  190. tweet.RoundPosted = 0
  191. tweetToReturn = tweet
  192. } else {
  193. //"copied" tweet
  194. //find tweet with pointers
  195. tweet = tmpdb[tweet.TopicPointer][tweet.TextPointer]
  196. tweet.RoundPosted = 0
  197. tweetToReturn = tweet
  198. }
  199. }
  200. //fmt.Println("nextTweet", tweetToReturn)
  201. var tweetToReturnBytes []byte
  202. for _, topic := range tweetToReturn.Topics {
  203. tweetToReturnBytes = append(tweetToReturnBytes, []byte(topic)...)
  204. tweetToReturnBytes = append(tweetToReturnBytes, ","...)
  205. }
  206. //replaces last "," with ";;" bc there is text following and not another topic
  207. tweetToReturnBytes = tweetToReturnBytes[:len(tweetToReturnBytes)-1]
  208. tweetToReturnBytes = append(tweetToReturnBytes, []byte(";;")[:]...)
  209. tweetToReturnBytes = append(tweetToReturnBytes, []byte(tweetToReturn.Text)...)
  210. tweetToReturnBytes = append(tweetToReturnBytes, []byte(";")[0])
  211. return tweetToReturnBytes, false
  212. }
  213. //see func name
  214. func GetTopicList(whereFrom int) ([]byte, int) {
  215. tmpTopicList := topicList
  216. if whereFrom == 1 {
  217. tmpTopicList = archiveTopicList
  218. }
  219. if (len(tmpTopicList)) == 0 {
  220. return nil, 0
  221. }
  222. topicByteArray := new(bytes.Buffer)
  223. json.NewEncoder(topicByteArray).Encode(tmpTopicList)
  224. return topicByteArray.Bytes(), len(tmpTopicList)
  225. }
  226. //iterates through full dbR and moves old tweets to archive
  227. func CleanUpdbR(round int) {
  228. if roundsBeforeArchiving == -1 {
  229. return
  230. }
  231. if roundsBeforeArchiving-round == 0 {
  232. keys := make([]string, len(dbR))
  233. i := 0
  234. for k := range dbR {
  235. keys[i] = k
  236. i++
  237. }
  238. sort.Strings(keys)
  239. var tweetsToArchive []Tweet
  240. for _, topic := range keys {
  241. tweets := dbR[topic]
  242. for i := len(tweets) - 1; i >= 0; i-- {
  243. if round-roundsBeforeArchiving+1 == tweets[i].RoundPosted {
  244. //only adds the tweet to the archive when there is text
  245. if tweets[i].Text != "" {
  246. tweetsToArchive = append(tweetsToArchive, tweets[i])
  247. }
  248. //delets the tweet from the array
  249. row := append(tweets[:i], tweets[i+1:]...)
  250. tweets = row
  251. }
  252. }
  253. dbR[topic] = tweets
  254. }
  255. NewEntries(tweetsToArchive, 1)
  256. roundsBeforeArchiving = roundsBeforeArchiving + roundsBeforeArchiving
  257. //redoes the whole dbR to correct pointers
  258. var tweetsToMain []Tweet
  259. for _, topic := range keys {
  260. tweets := dbR[topic]
  261. for _, tweet := range tweets {
  262. if tweet.Text != "" {
  263. //fmt.Println("tweet", tweet)
  264. tweetsToMain = append(tweetsToMain, tweet)
  265. }
  266. }
  267. }
  268. dbR = nil
  269. dbR = make(map[string][]Tweet)
  270. topicList = nil
  271. NewEntries(tweetsToMain, 0)
  272. }
  273. }
  274. func GetBytesSaved() float64 {
  275. return bytesSaved / float64(len(archive))
  276. }