databaseRead.go 7.9 KB

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