Advertisement
Guest User

Untitled

a guest
Oct 19th, 2018
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 7.72 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4.     "encoding/json"
  5.     "fmt"
  6.     "github.com/gorilla/mux"
  7.     "github.com/marni/goigc"
  8.     "log"
  9.     "math/rand"
  10.     "net/http"
  11.     "os"
  12.     "strconv"
  13.     "strings"
  14.     "time"
  15. )
  16. //time since the server starts
  17. var startTime = time.Now()
  18. var urlMap = make(map[int]string)
  19. var mapID int
  20. var uniqueId int
  21.  
  22.  
  23.  
  24.  
  25. type url struct {
  26.     URL string `json:"url"`
  27. }
  28.  
  29. //saves the igc files tracks
  30. var IGC_files []Track
  31.  
  32. //Struct that saves the ID and igcTrack data
  33. type Track struct {
  34.     ID string   `json:"ID"`
  35.     IGC_Track igc.Track `json:"igcTrack"`
  36. }
  37.  
  38. //Struct that saves meta information about the server
  39. type MetaInfo struct {
  40.     Uptime string       `json:"uptime"`
  41.     Info string         `json:"info"`
  42.     Version string      `json:"version"`
  43. }
  44.  
  45. // this function returns true if the index is not found and false otherwise
  46. func findIndex(x map[int]string,y int)bool{
  47.     for k, _ := range x {
  48.         if k == y{
  49.             return false
  50.         }
  51.     }
  52.     return true
  53. }
  54.  
  55. //this function the key of the string if the map contains it, or -1 if the map does not contain the string
  56. func searchMap(x map[int]string,y string)int{
  57.  
  58.     for k, v := range x {
  59.         if v==y{
  60.             return k
  61.         }
  62.     }
  63.     return -1
  64. }
  65.  
  66. func main(){
  67.  
  68.  
  69.     router := mux.NewRouter()
  70.  
  71.     router.HandleFunc("/igcinfo/", IGCinfo)
  72.     router.HandleFunc("/igcinfo/api",GETapi)
  73.     router.HandleFunc("/igcinfo/api/igc",getApiIGC)
  74.     router.HandleFunc("/igcinfo/api/igc/{id}", getApiIgcID)
  75.     router.HandleFunc("/igcinfo/api/igc/{id}/{field}", getApiIgcIDField)
  76.  
  77.     err := http.ListenAndServe(":"+os.Getenv("PORT"), router)
  78.     if err != nil {
  79.         log.Fatal("ListenAndServe: ", err)
  80.     }
  81.  
  82.  
  83. }
  84.  
  85. //this function gets the port assigned by heroku
  86. func GetAddr() string {
  87.     var port = os.Getenv("PORT")
  88.  
  89.     if port == "" {
  90.         port = "4747"
  91.         fmt.Println("No port  variable detected, defaulting to " + port)
  92.     }
  93.     return ":" + port
  94. }
  95.  
  96.  
  97.  
  98. func IGCinfo(w http.ResponseWriter, r *http.Request) {
  99.  
  100.     http.Error(w, "Error 404: Page not found!", http.StatusNotFound)
  101.     return
  102. }
  103.  
  104. func GETapi(w http.ResponseWriter, request *http.Request) {
  105.     w.Header().Set("content-type", "application/json")
  106.  
  107.     URLs := mux.Vars(request)
  108.     if len(URLs) != 0 {
  109.         http.Error(w, "400 - Bad Request!", http.StatusBadRequest)
  110.         return
  111.     }
  112.  
  113.     metaInfo := &MetaInfo{}
  114.     metaInfo.Uptime = FormatSince(startTime)
  115.     metaInfo.Info = "Service for IGC tracks"
  116.     metaInfo.Version = "version 1.0"
  117.  
  118.     json.NewEncoder(w).Encode(metaInfo)
  119. }
  120.  
  121. //request is what we get from the client
  122. func getApiIGC(w http.ResponseWriter, request *http.Request) {
  123.  
  124.     //request.method gives us the method selected by the client, in this api there are two methods
  125.     //that are implemented GET and POST, requests made for other methods will result to an error 501
  126.     //501 is an HTTP  error for not implemented
  127.     switch request.Method {
  128.  
  129.     case "GET":
  130.         w.Header().Set("content-type", "application/json")
  131.  
  132.         URLs := mux.Vars(request)
  133.         if len(URLs) != 0 {
  134.             http.Error(w, "400 - Bad Request!", 400)
  135.             return
  136.         }
  137.  
  138.         trackIDs := make([]string, 0, 0)
  139.  
  140.         for i := range IGC_files {
  141.             trackIDs = append(trackIDs, IGC_files[i].ID)
  142.         }
  143.  
  144.         json.NewEncoder(w).Encode(trackIDs)
  145.  
  146.  
  147.  
  148.  
  149.     case "POST":
  150.         // Set response content-type to JSON
  151.         w.Header().Set("content-type", "application/json")
  152.  
  153.         URLt := &url{}
  154.  
  155.  
  156.  
  157.         //Url is given to the server as JSON and now we decode it to a go structure
  158.         var error = json.NewDecoder(request.Body).Decode(URLt)
  159.         if error != nil {
  160.             http.Error(w,http.StatusText(400),400)
  161.             return
  162.         }
  163.  
  164.         //making a random unique ID for the track files
  165.         rand.Seed(time.Now().UnixNano())
  166.  
  167.  
  168.  
  169.         track, err := igc.ParseLocation(URLt.URL)
  170.         if err != nil {
  171.  
  172.             http.Error(w,"Bad request!\nMalformed URL!",400)
  173.             return
  174.         }
  175.  
  176.  
  177.         mapID = searchMap(urlMap,URLt.URL)
  178.         initialID := rand.Intn(100)
  179.  
  180.         if mapID == -1{
  181.             if findIndex(urlMap,initialID){
  182.                 uniqueId = initialID
  183.                 urlMap[uniqueId] = URLt.URL
  184.             } else{
  185.                 uniqueId = rand.Intn(100)
  186.                 urlMap[uniqueId] = URLt.URL
  187.             }
  188.  
  189.         } else {
  190.             uniqueId = searchMap(urlMap,URLt.URL)
  191.         }
  192.  
  193.  
  194.         igcFile := Track{}
  195.         igcFile.ID = strconv.Itoa(uniqueId)
  196.         igcFile.IGC_Track = track
  197.  
  198.  
  199.         if findIndex(urlMap,initialID){
  200.  
  201.             IGC_files = append(IGC_files, igcFile)
  202.         }
  203.  
  204.  
  205.         fmt.Fprint(w,"{\n\t\"id\": \""+igcFile.ID+"\"\n}")
  206.  
  207.  
  208.         //not implemented methods-->status:501
  209.  
  210.     default:
  211.         http.Error(w, "This method is not implemented!", 501)
  212.         return
  213.  
  214.     }
  215.  
  216.  
  217. }
  218.  
  219. func getApiIgcID(w http.ResponseWriter, request *http.Request) {
  220.  
  221.     w.Header().Set("content-type", "application/json")
  222.  
  223.     URLt := mux.Vars(request)
  224.     if len(URLt) != 1 {
  225.         http.Error(w, "400 - Bad Request!", http.StatusBadRequest)
  226.         return
  227.     }
  228.  
  229.     if URLt["id"] == "" {
  230.         http.Error(w, "400 - Bad Request!", http.StatusBadRequest)
  231.         return
  232.     }
  233.  
  234.     for i := range IGC_files {
  235.         //The requested meta information about a particular track based on the ID given in the url
  236.         //checking if the meta information about it is in memory if so the meta information will be returned
  237.         //otherwise it will return error 404, not found
  238.         if IGC_files[i].ID == URLt["id"] {
  239.             tDate := IGC_files[i].IGC_Track.Date.String()
  240.             tPilot := IGC_files[i].IGC_Track.Pilot
  241.             tGlider := IGC_files[i].IGC_Track.GliderType
  242.             tGliderId := IGC_files[i].IGC_Track.GliderID
  243.             tTrackLength := fmt.Sprintf("%f",trackLength(IGC_files[i].IGC_Track))
  244.             w.Header().Set("content-type","application/json")
  245.             fmt.Fprint(w,"{\n\"H_date\": \""+tDate+"\",\n\"pilot\": \""+tPilot+"\",\n\"GliderType\": \""+tGlider+"\",\n\"Glider_ID\": \""+tGliderId+"\",\n\"track_length\": \""+tTrackLength+"\"\n}")
  246.         }else{
  247.             http.Error(w,"",404)
  248.         }
  249.     }
  250.  
  251.  
  252. }
  253.  
  254. func getApiIgcIDField(w http.ResponseWriter, request *http.Request) {
  255.  
  256.  
  257.  
  258.     URLs := mux.Vars(request)
  259.     if len(URLs) != 2 {
  260.         w.Header().Set("content-type", "application/json")
  261.         http.Error(w, "Error 400 : Bad Request!", http.StatusBadRequest)
  262.         return
  263.     }
  264.  
  265.  
  266.     if URLs["id"] == "" {
  267.         w.Header().Set("content-type", "application/json")
  268.         http.Error(w, "Error 400 : Bad Request!\n You did not enter an ID.", http.StatusBadRequest)
  269.         return
  270.     }
  271.  
  272.     if URLs["field"] == "" {
  273.         w.Header().Set("content-type", "application/json")
  274.         http.Error(w, "Error 400 : Bad Request!\n You did not  enter a field.", http.StatusBadRequest)
  275.         return
  276.     }
  277.  
  278.  
  279.     for i := range IGC_files {
  280.         if IGC_files[i].ID == URLs["id"] {
  281.  
  282.             mapping := map[string]string {
  283.                 "pilot" : IGC_files[i].IGC_Track.Pilot,
  284.                 "glider" : IGC_files[i].IGC_Track.GliderType,
  285.                 "glider_id" : IGC_files[i].IGC_Track.GliderID,
  286.                 "track_length" : fmt.Sprintf("%f",trackLength(IGC_files[i].IGC_Track)),
  287.                 "h_date" : IGC_files[i].IGC_Track.Date.String(),
  288.             }
  289.  
  290.             field := URLs["field"]
  291.             field = strings.ToLower(field)
  292.  
  293.             if val, ok := mapping[field]; ok {
  294.                 fmt.Fprint(w,val)
  295.             } else {
  296.  
  297.  
  298.                 http.Error(w, "", 404)
  299.  
  300.                 return
  301.             }
  302.  
  303.         }
  304.  
  305.     }
  306. }
  307.  
  308.  
  309. //function calculating the total  distance of the flight, from the start point until end point(geographical coordinates)
  310. func trackLength(track igc.Track) float64 {
  311.  
  312.     totalDistance := 0.0
  313.  
  314.     for i := 0; i < len(track.Points)-1; i++ {
  315.         totalDistance += track.Points[i].Distance(track.Points[i+1])
  316.     }
  317.  
  318.     return totalDistance
  319. }
  320. // function that returns the current uptime of the service, format as specified by ISO 8601.
  321. func FormatSince(t time.Time) string {
  322.     const (
  323.         Decisecond = 100 * time.Millisecond
  324.         Day        = 24 * time.Hour
  325.     )
  326.     ts := time.Since(t)
  327.     sign := time.Duration(1)
  328.     if ts < 0 {
  329.         sign = -1
  330.         ts = -ts
  331.     }
  332.     ts += +Decisecond / 2
  333.     d := sign * (ts / Day)
  334.     ts = ts % Day
  335.     h := ts / time.Hour
  336.     ts = ts % time.Hour
  337.     m := ts / time.Minute
  338.     ts = ts % time.Minute
  339.     s := ts / time.Second
  340.     ts = ts % time.Second
  341.     f := ts / Decisecond
  342.     y := d / 365
  343.     return fmt.Sprintf("P%dY%dD%dH%dM%d.%dS", y, d, h, m, s, f)
  344. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement