You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

727 lines
16 KiB

  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "sort"
  7. "strconv"
  8. "time"
  9. "gopkg.in/mgo.v2/bson"
  10. "github.com/gorilla/mux"
  11. )
  12. type Routes []Route
  13. var routes = Routes{
  14. Route{
  15. "Index",
  16. "GET",
  17. "/",
  18. Index,
  19. },
  20. Route{
  21. "Stats",
  22. "Get",
  23. "/stats",
  24. Stats,
  25. },
  26. Route{
  27. "AllAddresses",
  28. "Get",
  29. "/alladdresses",
  30. AllAddresses,
  31. },
  32. Route{
  33. "Blocks",
  34. "Get",
  35. "/blocks/{page}/{count}",
  36. Blocks,
  37. },
  38. Route{
  39. "Txs",
  40. "Get",
  41. "/txs/{page}/{count}",
  42. Txs,
  43. },
  44. Route{
  45. "Addresses",
  46. "Get",
  47. "/addresses/{page}/{count}",
  48. Addresses,
  49. },
  50. Route{
  51. "Block",
  52. "GET",
  53. "/block/{height}",
  54. Block,
  55. },
  56. Route{
  57. "Tx",
  58. "GET",
  59. "/tx/{txid}",
  60. Tx,
  61. },
  62. Route{
  63. "Address",
  64. "GET",
  65. "/address/{hash}",
  66. Address,
  67. },
  68. Route{
  69. "AddressNetwork",
  70. "GET",
  71. "/address/network/{address}",
  72. AddressNetwork,
  73. },
  74. Route{
  75. "BlockSankey",
  76. "GET",
  77. "/block/{height}/sankey",
  78. BlockSankey,
  79. },
  80. Route{
  81. "TxSankey",
  82. "GET",
  83. "/tx/{txid}/sankey",
  84. TxSankey,
  85. },
  86. Route{
  87. "AddressSankey",
  88. "GET",
  89. "/address/sankey/{address}",
  90. AddressSankey,
  91. },
  92. Route{
  93. "NetworkMap",
  94. "Get",
  95. "/map",
  96. NetworkMap,
  97. },
  98. Route{
  99. "GetTotalHourAnalysis",
  100. "Get",
  101. "/totalhouranalysis",
  102. GetTotalHourAnalysis,
  103. },
  104. Route{
  105. "GetLast24HourAnalysis",
  106. "Get",
  107. "/last24hour",
  108. GetLast24HourAnalysis,
  109. },
  110. Route{
  111. "GetLast7DayAnalysis",
  112. "Get",
  113. "/last7day",
  114. GetLast7DayAnalysis,
  115. },
  116. Route{
  117. "GetLast7DayHourAnalysis",
  118. "Get",
  119. "/last7dayhour",
  120. GetLast7DayHourAnalysis,
  121. },
  122. Route{
  123. "GetAddressTimeChart",
  124. "GET",
  125. "/addresstimechart/{hash}",
  126. GetAddressTimeChart,
  127. },
  128. }
  129. //ROUTES
  130. func Index(w http.ResponseWriter, r *http.Request) {
  131. fmt.Fprintln(w, "ask for recommendations in /r")
  132. //http.FileServer(http.Dir("./web"))
  133. }
  134. /*
  135. func NewUser(w http.ResponseWriter, r *http.Request) {
  136. ipFilter(w, r)
  137. decoder := json.NewDecoder(r.Body)
  138. var newUser UserModel
  139. err := decoder.Decode(&newUser)
  140. check(err)
  141. defer r.Body.Close()
  142. saveUser(userCollection, newUser)
  143. fmt.Println(newUser)
  144. fmt.Fprintln(w, "new user added: ", newUser.ID)
  145. }
  146. */
  147. func Stats(w http.ResponseWriter, r *http.Request) {
  148. ipFilter(w, r)
  149. stats := getStats()
  150. jsonResp, err := json.Marshal(stats)
  151. check(err)
  152. fmt.Fprintln(w, string(jsonResp))
  153. }
  154. func AllAddresses(w http.ResponseWriter, r *http.Request) {
  155. ipFilter(w, r)
  156. nodes := []NodeModel{}
  157. iter := nodeCollection.Find(bson.M{"type": "address"}).Limit(10000).Iter()
  158. err := iter.All(&nodes)
  159. //convert []resp struct to json
  160. jsonNodes, err := json.Marshal(nodes)
  161. check(err)
  162. fmt.Fprintln(w, string(jsonNodes))
  163. }
  164. func Blocks(w http.ResponseWriter, r *http.Request) {
  165. ipFilter(w, r)
  166. vars := mux.Vars(r)
  167. page, err := strconv.Atoi(vars["page"])
  168. check(err)
  169. count, err := strconv.Atoi(vars["count"])
  170. check(err)
  171. blocks := []BlockModel{}
  172. err = blockCollection.Find(bson.M{}).Skip((page - 1) * 20).Limit(count).Sort("-$natural").All(&blocks)
  173. check(err)
  174. for _, block := range blocks {
  175. //blockheight := strconv.FormatInt(block.Height, 10)
  176. blockheight := block.Height
  177. txs := []TxModel{}
  178. err = txCollection.Find(bson.M{"blockheight": blockheight}).All(&txs)
  179. block.Txs = txs
  180. }
  181. //convert []resp struct to json
  182. jsonData, err := json.Marshal(blocks)
  183. check(err)
  184. fmt.Fprintln(w, string(jsonData))
  185. }
  186. func Txs(w http.ResponseWriter, r *http.Request) {
  187. ipFilter(w, r)
  188. vars := mux.Vars(r)
  189. page, err := strconv.Atoi(vars["page"])
  190. check(err)
  191. count, err := strconv.Atoi(vars["count"])
  192. check(err)
  193. txs := []TxModel{}
  194. err = txCollection.Find(bson.M{}).Skip((page - 1) * 20).Limit(count).Sort("-$natural").All(&txs)
  195. check(err)
  196. //convert []resp struct to json
  197. jsonData, err := json.Marshal(txs)
  198. check(err)
  199. fmt.Fprintln(w, string(jsonData))
  200. }
  201. func Addresses(w http.ResponseWriter, r *http.Request) {
  202. ipFilter(w, r)
  203. vars := mux.Vars(r)
  204. page, err := strconv.Atoi(vars["page"])
  205. check(err)
  206. count, err := strconv.Atoi(vars["count"])
  207. check(err)
  208. addresses := []AddressModel{}
  209. err = addressCollection.Find(bson.M{}).Skip((page - 1) * 20).Limit(count).Sort("-$natural").All(&addresses)
  210. check(err)
  211. //convert []resp struct to json
  212. jsonResp, err := json.Marshal(addresses)
  213. check(err)
  214. fmt.Fprintln(w, string(jsonResp))
  215. }
  216. func Block(w http.ResponseWriter, r *http.Request) {
  217. ipFilter(w, r)
  218. vars := mux.Vars(r)
  219. var heightString string
  220. heightString = vars["height"]
  221. height, err := strconv.ParseInt(heightString, 10, 64)
  222. if err != nil {
  223. fmt.Fprintln(w, "not valid height")
  224. } else {
  225. block := BlockModel{}
  226. err := blockCollection.Find(bson.M{"height": height}).One(&block)
  227. txs := []TxModel{}
  228. err = txCollection.Find(bson.M{"blockheight": heightString}).All(&txs)
  229. block.Txs = txs
  230. //convert []resp struct to json
  231. jsonResp, err := json.Marshal(block)
  232. check(err)
  233. fmt.Fprintln(w, string(jsonResp))
  234. }
  235. }
  236. func Tx(w http.ResponseWriter, r *http.Request) {
  237. ipFilter(w, r)
  238. vars := mux.Vars(r)
  239. txid := vars["txid"]
  240. if txid == "undefined" {
  241. fmt.Fprintln(w, "not valid txid")
  242. } else {
  243. tx := TxModel{}
  244. err := txCollection.Find(bson.M{"txid": txid}).One(&tx)
  245. //convert []resp struct to json
  246. jsonResp, err := json.Marshal(tx)
  247. check(err)
  248. fmt.Fprintln(w, string(jsonResp))
  249. }
  250. }
  251. func Address(w http.ResponseWriter, r *http.Request) {
  252. ipFilter(w, r)
  253. vars := mux.Vars(r)
  254. hash := vars["hash"]
  255. if hash == "undefined" {
  256. fmt.Fprintln(w, "not valid hash")
  257. } else {
  258. address := AddressModel{}
  259. err := addressCollection.Find(bson.M{"hash": hash}).One(&address)
  260. txs := []TxModel{}
  261. err = txCollection.Find(bson.M{"$or": []bson.M{bson.M{"vin.address": hash}, bson.M{"vout.address": hash}}}).All(&txs)
  262. address.Txs = txs
  263. for _, tx := range address.Txs {
  264. blocks := []BlockModel{}
  265. err = blockCollection.Find(bson.M{"hash": tx.BlockHash}).All(&blocks)
  266. for _, block := range blocks {
  267. address.Blocks = append(address.Blocks, block)
  268. }
  269. }
  270. //convert []resp struct to json
  271. jsonResp, err := json.Marshal(address)
  272. check(err)
  273. fmt.Fprintln(w, string(jsonResp))
  274. }
  275. }
  276. func AddressNetwork(w http.ResponseWriter, r *http.Request) {
  277. ipFilter(w, r)
  278. vars := mux.Vars(r)
  279. address := vars["address"]
  280. if address == "undefined" {
  281. fmt.Fprintln(w, "not valid address")
  282. } else {
  283. network := addressTree(address)
  284. network.Nodes[0].Shape = "triangle"
  285. //convert []resp struct to json
  286. jNetwork, err := json.Marshal(network)
  287. check(err)
  288. fmt.Fprintln(w, string(jNetwork))
  289. }
  290. }
  291. func BlockSankey(w http.ResponseWriter, r *http.Request) {
  292. ipFilter(w, r)
  293. vars := mux.Vars(r)
  294. var heightString string
  295. heightString = vars["height"]
  296. height, err := strconv.ParseInt(heightString, 10, 64)
  297. if err != nil {
  298. fmt.Fprintln(w, "not valid height")
  299. } else {
  300. block := BlockModel{}
  301. err := blockCollection.Find(bson.M{"height": height}).One(&block)
  302. txs := []TxModel{}
  303. err = txCollection.Find(bson.M{"blockheight": heightString}).All(&txs)
  304. block.Txs = txs
  305. var nodesCount int
  306. mapNodeK := make(map[string]int)
  307. var sankey SankeyModel
  308. for _, tx := range block.Txs {
  309. var sankeyNodeA SankeyNodeModel
  310. sankeyNodeA.Node = nodesCount
  311. mapNodeK["tx"] = nodesCount
  312. nodesCount++
  313. sankeyNodeA.Name = "tx"
  314. sankey.Nodes = append(sankey.Nodes, sankeyNodeA)
  315. for _, vin := range tx.Vin {
  316. var sankeyNode SankeyNodeModel
  317. sankeyNode.Node = nodesCount
  318. mapNodeK[vin.Address] = nodesCount
  319. nodesCount++
  320. sankeyNode.Name = vin.Address
  321. sankey.Nodes = append(sankey.Nodes, sankeyNode)
  322. var sankeyLink SankeyLinkModel
  323. sankeyLink.Source = mapNodeK[vin.Address]
  324. sankeyLink.Target = mapNodeK["tx"]
  325. sankeyLink.Value = vin.Amount
  326. fmt.Println(sankeyLink)
  327. sankey.Links = append(sankey.Links, sankeyLink)
  328. fmt.Println(sankey.Links)
  329. }
  330. for _, vout := range tx.Vout {
  331. var sankeyNode SankeyNodeModel
  332. sankeyNode.Node = nodesCount
  333. mapNodeK[vout.Address] = nodesCount
  334. nodesCount++
  335. sankeyNode.Name = vout.Address
  336. sankey.Nodes = append(sankey.Nodes, sankeyNode)
  337. var sankeyLink SankeyLinkModel
  338. sankeyLink.Source = mapNodeK["tx"]
  339. sankeyLink.Target = mapNodeK[vout.Address]
  340. sankeyLink.Value = vout.Value
  341. fmt.Println(sankeyLink)
  342. sankey.Links = append(sankey.Links, sankeyLink)
  343. }
  344. }
  345. fmt.Println("Sankey generated")
  346. fmt.Println(sankey)
  347. //convert []resp struct to json
  348. jsonSankey, err := json.Marshal(sankey)
  349. check(err)
  350. fmt.Fprintln(w, string(jsonSankey))
  351. }
  352. }
  353. func TxSankey(w http.ResponseWriter, r *http.Request) {
  354. ipFilter(w, r)
  355. vars := mux.Vars(r)
  356. txid := vars["txid"]
  357. if txid == "undefined" {
  358. fmt.Fprintln(w, "not valid height")
  359. } else {
  360. tx := TxModel{}
  361. err := txCollection.Find(bson.M{"txid": txid}).One(&tx)
  362. var nodesCount int
  363. mapNodeK := make(map[string]int)
  364. var sankey SankeyModel
  365. var sankeyNodeA SankeyNodeModel
  366. sankeyNodeA.Node = nodesCount
  367. mapNodeK["tx"] = nodesCount
  368. nodesCount++
  369. sankeyNodeA.Name = "tx"
  370. sankey.Nodes = append(sankey.Nodes, sankeyNodeA)
  371. fmt.Println(tx.Vin)
  372. for _, vin := range tx.Vin {
  373. var sankeyNode SankeyNodeModel
  374. sankeyNode.Node = nodesCount
  375. mapNodeK[vin.Address] = nodesCount
  376. nodesCount++
  377. sankeyNode.Name = vin.Address
  378. sankey.Nodes = append(sankey.Nodes, sankeyNode)
  379. var sankeyLink SankeyLinkModel
  380. sankeyLink.Source = mapNodeK[vin.Address]
  381. sankeyLink.Target = mapNodeK["tx"]
  382. sankeyLink.Value = vin.Amount
  383. sankey.Links = append(sankey.Links, sankeyLink)
  384. }
  385. for _, vout := range tx.Vout {
  386. var sankeyNode SankeyNodeModel
  387. sankeyNode.Node = nodesCount
  388. mapNodeK[vout.Address] = nodesCount
  389. nodesCount++
  390. sankeyNode.Name = vout.Address
  391. sankey.Nodes = append(sankey.Nodes, sankeyNode)
  392. var sankeyLink SankeyLinkModel
  393. sankeyLink.Source = mapNodeK["tx"]
  394. sankeyLink.Target = mapNodeK[vout.Address]
  395. sankeyLink.Value = vout.Value
  396. sankey.Links = append(sankey.Links, sankeyLink)
  397. }
  398. fmt.Println("Sankey generated")
  399. //convert []resp struct to json
  400. jsonSankey, err := json.Marshal(sankey)
  401. check(err)
  402. fmt.Fprintln(w, string(jsonSankey))
  403. }
  404. }
  405. func AddressSankey(w http.ResponseWriter, r *http.Request) {
  406. ipFilter(w, r)
  407. vars := mux.Vars(r)
  408. address := vars["address"]
  409. if address == "undefined" {
  410. fmt.Fprintln(w, "not valid address")
  411. } else {
  412. network := addressTree(address)
  413. var sankey SankeyModel
  414. fmt.Println("network generated")
  415. mapNodeK := make(map[string]int)
  416. for k, n := range network.Nodes {
  417. var sankeyNode SankeyNodeModel
  418. //sankeyNode.StringNode = n.Id
  419. sankeyNode.Node = k
  420. sankeyNode.Name = n.Id
  421. sankey.Nodes = append(sankey.Nodes, sankeyNode)
  422. mapNodeK[n.Id] = k
  423. }
  424. for _, e := range network.Edges {
  425. var sankeyLink SankeyLinkModel
  426. //sankeyLink.StringSource = e.From
  427. sankeyLink.Source = mapNodeK[e.From]
  428. //sankeyLink.StringTarget = e.To
  429. sankeyLink.Target = mapNodeK[e.To]
  430. sankeyLink.Value = e.Label
  431. sankey.Links = append(sankey.Links, sankeyLink)
  432. }
  433. fmt.Println("Sankey generated")
  434. //convert []resp struct to json
  435. jsonSankey, err := json.Marshal(sankey)
  436. check(err)
  437. fmt.Fprintln(w, string(jsonSankey))
  438. }
  439. }
  440. func NetworkMap(w http.ResponseWriter, r *http.Request) {
  441. ipFilter(w, r)
  442. nodes, err := getAllNodes()
  443. check(err)
  444. edges, err := getAllEdges()
  445. check(err)
  446. var network NetworkModel
  447. network.Nodes = nodes
  448. network.Edges = edges
  449. //convert []resp struct to json
  450. jNetwork, err := json.Marshal(network)
  451. check(err)
  452. fmt.Fprintln(w, string(jNetwork))
  453. }
  454. func GetTotalHourAnalysis(w http.ResponseWriter, r *http.Request) {
  455. ipFilter(w, r)
  456. hourAnalysis := []ChartCountModel{}
  457. iter := hourCountCollection.Find(bson.M{}).Limit(10000).Iter()
  458. err := iter.All(&hourAnalysis)
  459. //sort by hour
  460. sort.Slice(hourAnalysis, func(i, j int) bool {
  461. return hourAnalysis[i].Elem < hourAnalysis[j].Elem
  462. })
  463. var resp ChartAnalysisResp
  464. for _, d := range hourAnalysis {
  465. resp.Labels = append(resp.Labels, strconv.Itoa(d.Elem))
  466. resp.Data = append(resp.Data, d.Count)
  467. }
  468. //convert []resp struct to json
  469. jsonResp, err := json.Marshal(resp)
  470. check(err)
  471. fmt.Fprintln(w, string(jsonResp))
  472. }
  473. func GetLast24HourAnalysis(w http.ResponseWriter, r *http.Request) {
  474. ipFilter(w, r)
  475. fromDate := time.Now().AddDate(0, 0, -1)
  476. toDate := time.Now()
  477. txs := []TxModel{}
  478. err := txCollection.Find(bson.M{
  479. "datet": bson.M{
  480. "$gt": fromDate,
  481. "$lt": toDate,
  482. },
  483. }).Sort("-$natural").All(&txs)
  484. check(err)
  485. //generate map with 24 hours
  486. hourFrequencies := map24hours()
  487. for _, tx := range txs {
  488. hourFrequencies[tx.Date.Hour]++
  489. }
  490. var hourCount []ChartCountModel
  491. for hour, frequency := range hourFrequencies {
  492. hourCount = append(hourCount, ChartCountModel{hour, frequency})
  493. }
  494. //sort by hour
  495. sort.Slice(hourCount, func(i, j int) bool {
  496. return hourCount[i].Elem < hourCount[j].Elem
  497. })
  498. var resp ChartAnalysisResp
  499. for _, d := range hourCount {
  500. resp.Labels = append(resp.Labels, strconv.Itoa(d.Elem))
  501. resp.Data = append(resp.Data, d.Count)
  502. }
  503. //convert []resp struct to json
  504. jsonResp, err := json.Marshal(resp)
  505. check(err)
  506. fmt.Fprintln(w, string(jsonResp))
  507. }
  508. func GetLast7DayAnalysis(w http.ResponseWriter, r *http.Request) {
  509. ipFilter(w, r)
  510. fromDate := time.Now().AddDate(0, 0, -7)
  511. toDate := time.Now()
  512. txs := []TxModel{}
  513. err := txCollection.Find(bson.M{
  514. "datet": bson.M{
  515. "$gt": fromDate,
  516. "$lt": toDate,
  517. },
  518. }).Sort("-$natural").All(&txs)
  519. check(err)
  520. //generate map with 24 hours
  521. //hourFrequencies := map24hours()
  522. dayFrequencies := make(map[int]int)
  523. for _, tx := range txs {
  524. dayFrequencies[tx.Date.Day]++
  525. }
  526. var dayCount []ChartCountModel
  527. for day, frequency := range dayFrequencies {
  528. dayCount = append(dayCount, ChartCountModel{day, frequency})
  529. }
  530. //sort by hour
  531. sort.Slice(dayCount, func(i, j int) bool {
  532. return dayCount[i].Elem < dayCount[j].Elem
  533. })
  534. var resp ChartAnalysisResp
  535. for _, d := range dayCount {
  536. resp.Labels = append(resp.Labels, strconv.Itoa(d.Elem))
  537. resp.Data = append(resp.Data, d.Count)
  538. }
  539. //convert []resp struct to json
  540. jsonResp, err := json.Marshal(resp)
  541. check(err)
  542. fmt.Fprintln(w, string(jsonResp))
  543. }
  544. func GetLast7DayHourAnalysis(w http.ResponseWriter, r *http.Request) {
  545. ipFilter(w, r)
  546. var resp ChartSeriesAnalysisResp
  547. for i := 0; i < 7; i++ {
  548. fromDate := time.Now().AddDate(0, 0, -i-1)
  549. toDate := time.Now().AddDate(0, 0, -i)
  550. txs := []TxModel{}
  551. err := txCollection.Find(bson.M{
  552. "datet": bson.M{
  553. "$gt": fromDate,
  554. "$lt": toDate,
  555. },
  556. }).Sort("-$natural").All(&txs)
  557. check(err)
  558. //generate map with 24 hours
  559. hourFrequencies := map24hours()
  560. for _, tx := range txs {
  561. hourFrequencies[tx.Date.Hour]++
  562. }
  563. var hourCount []ChartCountModel
  564. for hour, frequency := range hourFrequencies {
  565. hourCount = append(hourCount, ChartCountModel{hour, frequency})
  566. }
  567. //sort by hour
  568. sort.Slice(hourCount, func(i, j int) bool {
  569. return hourCount[i].Elem < hourCount[j].Elem
  570. })
  571. var dayData []int
  572. for _, d := range hourCount {
  573. dayData = append(dayData, d.Count)
  574. }
  575. if len(txs) > 0 {
  576. resp.Series = append(resp.Series, txs[0].Date.Day)
  577. resp.Data = append(resp.Data, dayData)
  578. }
  579. }
  580. hourLabels := []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"}
  581. resp.Labels = hourLabels
  582. //convert []resp struct to json
  583. jsonResp, err := json.Marshal(resp)
  584. check(err)
  585. fmt.Fprintln(w, string(jsonResp))
  586. }
  587. func GetAddressTimeChart(w http.ResponseWriter, r *http.Request) {
  588. ipFilter(w, r)
  589. vars := mux.Vars(r)
  590. hash := vars["hash"]
  591. if hash == "undefined" {
  592. fmt.Fprintln(w, "not valid hash")
  593. } else {
  594. address := AddressModel{}
  595. err := addressCollection.Find(bson.M{"hash": hash}).One(&address)
  596. txs := []TxModel{}
  597. err = txCollection.Find(bson.M{"$or": []bson.M{bson.M{"vin.address": hash}, bson.M{"vout.address": hash}}}).All(&txs)
  598. address.Txs = txs
  599. for _, tx := range address.Txs {
  600. blocks := []BlockModel{}
  601. err = blockCollection.Find(bson.M{"hash": tx.BlockHash}).All(&blocks)
  602. for _, block := range blocks {
  603. address.Blocks = append(address.Blocks, block)
  604. }
  605. }
  606. count := make(map[time.Time]float64)
  607. for _, tx := range txs {
  608. var val float64
  609. for _, vin := range tx.Vin {
  610. val = val + vin.Amount
  611. }
  612. count[tx.DateT] = val
  613. }
  614. var dateSorted []time.Time
  615. for t, _ := range count {
  616. dateSorted = append(dateSorted, t)
  617. }
  618. sort.Slice(dateSorted, func(i, j int) bool {
  619. //return dateSorted[i] < dateSorted[j]
  620. return dateBeforeThan(dateSorted[i], dateSorted[j])
  621. })
  622. var resp ChartAnalysisRespFloat64
  623. for _, t := range dateSorted {
  624. resp.Labels = append(resp.Labels, t.String())
  625. resp.Data = append(resp.Data, count[t])
  626. }
  627. //convert []resp struct to json
  628. jsonResp, err := json.Marshal(resp)
  629. check(err)
  630. fmt.Fprintln(w, string(jsonResp))
  631. }
  632. }