databaseRead.go 8.1 KB

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