Skip to content

Commit

Permalink
feat: frontend v1 (#3)
Browse files Browse the repository at this point in the history
* feat: basic ui

* feat: first websocket implementation

* feat: front: websocket open & receive messages

* feat: back: fix websocket

* feat: satellite name in API response & polar view

* feat: show sat visibility in tracking response

* fix: fix prop-types for PolarView

* feat: satellite tracking by it's catalog number & basic error handling

* fix: eslint

* fix: eslint & prettier
  • Loading branch information
SharkEzz authored Jan 2, 2022
1 parent f03705f commit 76155e9
Show file tree
Hide file tree
Showing 27 changed files with 4,849 additions and 169 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ jobs:
- name: Test
run: go test -v ./...

lint-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '16'

- name: Install dependencies
run: npm --prefix js i

- name: Run ESLint
run: npm --prefix js run eslint

build-frontend:
runs-on: ubuntu-latest
steps:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
database/local.db
sattrack
data
public
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
# SatTrack

Modern satellite tracking solution
Modern satellite tracking solution (currently WIP)

![](img/home.png)

## TODO

### Backend

- [ ] Custom validation messages
- [ ] Check for performance issues & missing best practises
- [ ] API documentation
- [ ] Rate-limiting

### Frontend

- [ ] Migrate to Typescript
- [ ] About page
- [ ] Custom UI (Currently using Bootstrap 💀) + enhancements
- [ ] More functionalities (pass prediction, elevation/azimuth graph)
- [ ] GitHub action for ESLint

### Docker

- [ ] Dockerhub tag (currently it is only tagging with 'latest')
7 changes: 7 additions & 0 deletions dto/Tracking.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,10 @@ type TrackingResponse struct {
sgp4.Observation
GeneratedAt time.Time
}

type ObservationWsResponse struct {
SatelliteName string
Visible bool
GeneratedAt time.Time
sgp4.Observation
}
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ require (
require (
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.9.0
github.com/go-playground/validator/v10 v10.10.0
github.com/leodido/go-urn v1.2.1 // indirect
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect
golang.org/x/text v0.3.6 // indirect
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
golang.org/x/text v0.3.7 // indirect
)

require (
Expand All @@ -29,7 +29,7 @@ require (

require (
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/gofiber/fiber/v2 v2.23.0
github.com/gofiber/fiber/v2 v2.24.0
github.com/klauspost/compress v1.13.6 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.31.0 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A=
github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/gofiber/fiber/v2 v2.23.0 h1:kcJGMC6SULJ2G7p7mbs+A28cVLOeJSR694jfGyGZqRI=
github.com/gofiber/fiber/v2 v2.23.0/go.mod h1:MR1usVH3JHYRyQwMe2eZXRSZHRX38fkV+A7CPB+DlDQ=
github.com/gofiber/fiber/v2 v2.24.0 h1:18rpLoQMJBVlLtX/PwgHj3hIxPSeWfN1YeDJ2lEnzjU=
github.com/gofiber/fiber/v2 v2.24.0/go.mod h1:MR1usVH3JHYRyQwMe2eZXRSZHRX38fkV+A7CPB+DlDQ=
github.com/gofiber/websocket/v2 v2.0.14 h1:9xGDX08jBm1N809Q25MT95y0c72XvIguxsYKo3qG8ec=
github.com/gofiber/websocket/v2 v2.0.14/go.mod h1:movf9ZfhvBRpmZjwdv1u/gCvOPFjwznwqz+x75pYr7I=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
Expand Down Expand Up @@ -65,6 +69,8 @@ github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7Fw
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand All @@ -78,6 +84,8 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
13 changes: 11 additions & 2 deletions handlers/TrackingHandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package handlers

import (
"net/http"
"strings"
"time"

"github.com/SharkEzz/sattrack/dto"
Expand Down Expand Up @@ -75,8 +76,16 @@ func HandleWsTracking(c *websocket.Conn, db *gorm.DB) {

for {
observation := sgp4.ObservationFromLocation(lat, lng, alt)
if err := c.WriteJSON(observation); err != nil {
// error
responseDto := dto.ObservationWsResponse{
SatelliteName: strings.TrimSpace(tle.Name()),
Visible: observation.Elevation > 0,
GeneratedAt: time.Now().UTC(),
Observation: observation,
}
if err := c.WriteJSON(responseDto); err != nil {
return
}
if _, _, err = c.ReadMessage(); err != nil {
return
}
time.Sleep(time.Second)
Expand Down
Binary file added img/home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions js/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"airbnb",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
"prettier"
],
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["react", "react-hooks", "prettier"],
"rules": {
"prettier/prettier": "error",
"react/jsx-props-no-spreading": 0
}
}
37 changes: 37 additions & 0 deletions js/hooks/useLocation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useState } from 'react';

function useLocation() {
const [initialized, setInitialized] = useState(false);
const [location, setLocation] = useState({
lat: null,
lng: null,
alt: null,
});

const getLocation = () => {
if (typeof navigator === 'undefined' || !('geolocation' in navigator)) {
return;
}

navigator.geolocation.getCurrentPosition(
(position) => {
const { latitude, longitude, altitude } = position.coords;
setLocation({
lat: Number(latitude.toFixed(2)),
lng: Number(longitude.toFixed(2)),
alt: altitude ? Number(altitude.toFixed(2)) : null,
});
setInitialized(true);
},
() => null,
);
};

return {
initialized,
location,
getLocation,
};
}

export default useLocation;
76 changes: 76 additions & 0 deletions js/hooks/useWebsocket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { useRef, useState } from 'react';

function useWebsocket() {
const [opened, setOpened] = useState(false);
const [message, setMessage] = useState(null);
const [error, setError] = useState(null);
const [isOpening, setIsOpening] = useState(false);
const [isClosing, setIsClosing] = useState(false);
const websocket = useRef(null);

/**
* @param {MessageEvent} event
*/
const handleMessage = (event) => {
const receivedMessage = JSON.parse(event.data);
if (receivedMessage?.Status && receivedMessage.Status !== 200) {
setError({
status: receivedMessage.Status,
message: receivedMessage.Message,
});
return;
}
if (error) {
setError(null);
}
setMessage(receivedMessage);
websocket.current.send('ok');
};

const handleClose = () => {
setOpened(false);
setIsClosing(false);
};

const handleOpen = () => {
setOpened(true);
setIsOpening(false);
};

const closeConnection = () => {
websocket.current.close();
setIsClosing(true);
};

/**
* @param {String} baseUrl
* @param {Number} catNbr
* @param {{ lat: Number, lng: Number, alt: Number }} location
*/
const openConnection = (baseUrl, catNbr, location) => {
const url = new URL(baseUrl);
url.searchParams.append('catnbr', catNbr);
Object.keys(location).forEach((item) => {
url.searchParams.append(item, location[item]);
});

websocket.current = new WebSocket(url);
websocket.current.onclose = handleClose;
websocket.current.onopen = handleOpen;
websocket.current.onmessage = handleMessage;
websocket.current.onerror = closeConnection;
setIsOpening(true);
};

return {
isOpening,
isClosing,
opened,
message,
error,
openConnection,
closeConnection,
};
}

export default useWebsocket;
25 changes: 14 additions & 11 deletions js/index.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SatTrack</title>
</head>

<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>

</html>
Loading

0 comments on commit 76155e9

Please sign in to comment.