Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
834 changes: 787 additions & 47 deletions README.md

Large diffs are not rendered by default.

2,534 changes: 2,358 additions & 176 deletions doc/postman_collection

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions internal/cache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package cache

type moonCache struct {
}

type positionCache struct {
}
6 changes: 3 additions & 3 deletions internal/server/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ func round(num float64) int {
return int(num + math.Copysign(0.5, num))
}

func toFixed(num float64, precision int) float64 {
func ToFixed(num float64, precision int) float64 {
output := math.Pow(10, float64(precision))
return float64(round(num*output)) / output
}

func strToInt(val string, fallback int, min int, max int) int {
func StrToInt(val string, fallback int, min int, max int) int {
v, err := strconv.Atoi(val)
if err != nil {
v = fallback
Expand Down Expand Up @@ -48,7 +48,7 @@ func parseCoords(latStr, lonStr string) Coordinates {
return locationCords
}

func isValidDate(year, month, day int) error {
func IsValidDate(year, month, day int) error {
if year < 0 || year > 9999 {
return errors.New("'year' should be in range [0,9999]")
}
Expand Down
20 changes: 13 additions & 7 deletions internal/server/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ import (
"time"
)

type MoonTable struct {
Table []*moon.MoonTableElement
type ErrorPrintable struct {
Status int
Message string
}

type MoonStat struct {
MoonDays float64
Illumination float64
Phase phase.PhaseResp
Phase *phase.Phase
Zodiac zodiac.Zodiac
Position *pos.MoonPosition `json:"MoonPosition,omitempty"`
}
Expand All @@ -36,20 +37,25 @@ type MoonDay struct {
}

type MoonPhaseResponse struct {
BeginDay *MoonStat
CurrentState *MoonStat
EndDay *MoonStat
BeginDay *MoonStat `json:"BeginDay,omitempty"`
CurrentState *MoonStat `json:"CurrentState,omitempty"`
EndDay *MoonStat `json:"EndDay,omitempty"`

MoonDaysDetailed *moon.MoonDaysDetailed `json:"MoonDaysDetailed,omitempty"`
ZodiacDetailed *zodiac.Zodiacs

MoonRiseAndSet *pos.DayData `json:"MoonRiseAndSet,omitempty"`

info *FullInfo
//info *FullInfo
}

type Coordinates struct {
Latitude float64
Longitude float64
IsValid bool
}

type JulianTimeResp struct {
CivilDate *any
JulianDate float64
}
115 changes: 115 additions & 0 deletions internal/server/route-jtime.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package server

import (
"strconv"
"strings"
"time"

"github.com/gofiber/fiber/v2"

jt "moon/pkg/julian-time"
)

/* Julian Time methods */
func (s *Server) toJulianTimeByDateV1(c *fiber.Ctx) error {
tNow := time.Now()
tNow = tNow.In(time.UTC)

precision := StrToInt(c.Query("precision", "2"), 2, 0, 20)

year := StrToInt(c.Query("year", strconv.Itoa(tNow.Year())), tNow.Year(), 1, 9999)
month := StrToInt(c.Query("month", strconv.Itoa(int(tNow.Month()))), int(tNow.Month()), 1, 12)
day := StrToInt(c.Query("day", strconv.Itoa(int(tNow.Day()))), int(tNow.Day()), 1, 31)

timeFormat := c.Query("timeFormat", "ISO")

err := IsValidDate(year, month, day)
if err != nil {
c.Status(400)
errPrintable := ErrorPrintable{
Status: 400,
Message: "Validation error: " + err.Error(),
}
return c.JSON(errPrintable)
}

hour := StrToInt(c.Query("hour", strconv.Itoa(int(tNow.Hour()))), int(tNow.Hour()), 0, 23)
minute := StrToInt(c.Query("minute", strconv.Itoa(int(tNow.Minute()))), int(tNow.Minute()), 0, 59)
second := StrToInt(c.Query("second", strconv.Itoa(int(tNow.Second()))), int(tNow.Second()), 0, 59)

tGiven := time.Date(year, jt.GetMonth(month), day, hour, minute, second, 0, time.UTC)

resp := s.toJulianTimeV1(c, tGiven, timeFormat, precision)
return c.JSON(resp)
}

func (s *Server) toJulianTimeByTimestampV1(c *fiber.Ctx) error {
tStr := c.Query("timestamp", strconv.FormatInt(time.Now().Unix(), 10))
t, err := strconv.ParseInt(tStr, 10, 64)
if err != nil {
t = time.Now().Unix()
}

timeFormat := c.Query("timeFormat", "ISO")
precision := StrToInt(c.Query("precision", "2"), 2, 0, 20)

tm := time.Unix(t, 0)
tGiven := time.Date(tm.Year(), tm.Month(), tm.Day(), tm.Hour(), tm.Minute(), tm.Second(), 0, time.Local)
tGiven = tGiven.In(time.UTC)

resp := s.toJulianTimeV1(c, tGiven, timeFormat, precision)
return c.JSON(resp)
}

func (s *Server) toJulianTimeV1(c *fiber.Ctx, tGiven time.Time, timeFormat string, precision int) JulianTimeResp {
resp := JulianTimeResp{}

var t any
if strings.ToLower(timeFormat) == "timestamp" {
t = tGiven.Unix()
} else if strings.ToLower(timeFormat) != "iso" {
t = tGiven.Format(timeFormat)
} else {
t = tGiven
}

resp.CivilDate = &t
resp.JulianDate = ToFixed(jt.ToJulianDate(tGiven), precision)
return resp
}

func (s *Server) fromJulianTimeV1(c *fiber.Ctx) error {
utc := c.Query("utc", "UTC:+0")
loc, _ := jt.SetTimezoneLocFromString(utc)

jtStr := c.Query("jtime", "none")
jtime, err := strconv.ParseFloat(jtStr, 64)
if err != nil {
c.Status(400)
errPrintable := ErrorPrintable{
Status: 400,
Message: "missing required parameter: 'jtime' (float)",
}
return c.JSON(errPrintable)
}

t := jt.FromJulianDate(jtime, loc)

precision := StrToInt(c.Query("precision", "2"), 2, 0, 20)
timeFormat := c.Query("timeFormat", "ISO")

var tFormat any
if strings.ToLower(timeFormat) == "timestamp" {
tFormat = t.Unix()
} else if strings.ToLower(timeFormat) != "iso" {
tFormat = t.Format(timeFormat)
} else {
tFormat = t
}

resp := JulianTimeResp{}
resp.CivilDate = &tFormat
resp.JulianDate = ToFixed(jtime, precision)

return c.JSON(resp)
}
71 changes: 71 additions & 0 deletions internal/server/route-moon-table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package server

import (
jt "moon/pkg/julian-time"
"moon/pkg/moon"
"strconv"
"strings"
"time"

"github.com/gofiber/fiber/v2"
)

/* MOON TABLE */
func (s *Server) moonTableCurrentV1(c *fiber.Ctx) error {
utc := c.Query("utc", "UTC:+0")
loc, _ := jt.SetTimezoneLocFromString(utc)
/*if err != nil {
log.Println(err)
}*/

timeFormat := c.Query("timeFormat", "ISO")

tGiven := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute(), time.Now().Second(), 0, loc)
return s.moonTableV1(c, timeFormat, tGiven)
}

func (s *Server) moonTableYearV1(c *fiber.Ctx) error {
utc := c.Query("utc", "UTC:+0")
loc, _ := jt.SetTimezoneLocFromString(utc)
/*if err != nil {
log.Println(err)
}*/

timeFormat := c.Query("timeFormat", "ISO")

tNow := time.Now()
year := StrToInt(c.Query("year", strconv.Itoa(tNow.Year())), tNow.Year(), 1, 9999)

tGiven := time.Date(year, time.January, 1, 0, 0, 0, 0, loc)
return s.moonTableV1(c, timeFormat, tGiven)
}

func (s *Server) moonTableV1(c *fiber.Ctx, timeFormat string, tGiven time.Time) error {
moonTable := moon.CreateMoonTable(tGiven)

if strings.ToLower(timeFormat) == "timestamp" {
val := []moon.NearestPhaseTimestamp{}
for i := range moonTable.Elems {
val = append(val, moon.NearestPhaseTimestamp{
NewMoon: moonTable.Elems[i].NewMoon.Unix(),
FirstQuarter: moonTable.Elems[i].FirstQuarter.Unix(),
FullMoon: moonTable.Elems[i].FullMoon.Unix(),
LastQuarter: moonTable.Elems[i].FullMoon.Unix(),
})
}
return c.JSON(val)
} else if strings.ToLower(timeFormat) != "iso" {
val := []moon.NearestPhaseString{}
for i := range moonTable.Elems {
val = append(val, moon.NearestPhaseString{
NewMoon: moonTable.Elems[i].NewMoon.Format(timeFormat),
FirstQuarter: moonTable.Elems[i].FirstQuarter.Format(timeFormat),
FullMoon: moonTable.Elems[i].FullMoon.Format(timeFormat),
LastQuarter: moonTable.Elems[i].FullMoon.Format(timeFormat),
})
}
return c.JSON(val)
}

return c.JSON(moonTable.Elems)
}
104 changes: 104 additions & 0 deletions internal/server/route-next.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package server

import (
jt "moon/pkg/julian-time"
"moon/pkg/moon"
"strconv"
"strings"
"time"

"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/log"
)

func (s *Server) moonNextMoonPhaseV1(c *fiber.Ctx) error {
utc := c.Query("utc", "UTC:+0")
loc, _ := jt.SetTimezoneLocFromString(utc)
tGiven := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute(), time.Now().Second(), time.Now().Nanosecond(), time.Local)
tGiven = tGiven.In(loc)

moonTable := moon.CreateMoonTable(tGiven)
np := moon.FindNearestPhase(tGiven, moonTable)

format := c.Query("timeFormat", "ISO")
if strings.ToLower(format) == "timestamp" {
npt := moon.NearestPhaseTimestamp{
NewMoon: np.NewMoon.Unix(),
FirstQuarter: np.FirstQuarter.Unix(),
FullMoon: np.FullMoon.Unix(),
LastQuarter: np.LastQuarter.Unix(),
}
return c.JSON(npt)
} else if strings.ToLower(format) == "duration" {
npd := moon.NearestPhaseTimestamp{
NewMoon: np.NewMoon.Unix() - tGiven.Unix(),
FirstQuarter: np.FirstQuarter.Unix() - tGiven.Unix(),
FullMoon: np.FullMoon.Unix() - tGiven.Unix(),
LastQuarter: np.LastQuarter.Unix() - tGiven.Unix(),
}
return c.JSON(npd)
} else if strings.ToLower(format) == "iso" {
return c.JSON(np)
} else {
npc := moon.NearestPhaseString{
NewMoon: np.NewMoon.Format(format),
FirstQuarter: np.FirstQuarter.Format(format),
FullMoon: np.FullMoon.Format(format),
LastQuarter: np.LastQuarter.Format(format),
}
return c.JSON(npc)
}
}

func (s *Server) moonNextMoonDayV1(c *fiber.Ctx) error {
utc := c.Query("utc", "UTC:+0")
loc, _ := jt.SetTimezoneLocFromString(utc)
day := c.Query("day", "not-set")
if day == "not-set" {
e := ErrorPrintable{Status: 400, Message: "day is required for this method."}
return c.JSON(e)
}
dayInt, err := strconv.Atoi(day)
if err != nil {
e := ErrorPrintable{Status: 400, Message: "day is required to be int."}
return c.JSON(e)
}
if dayInt < 0 || dayInt > 30 {
e := ErrorPrintable{Status: 400, Message: "day is required to be [0, 30]. No other days allowed!"}
return c.JSON(e)
}

tGiven := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute(), time.Now().Second(), time.Now().Nanosecond(), time.Local)
tGiven = tGiven.In(loc)

moonTable := moon.CreateMoonTable(tGiven)
resp, err := moon.SearchMoonDay(tGiven, moonTable, dayInt)
if err != nil {
log.Error(err)
e := ErrorPrintable{Status: 500, Message: "bad things happen: " + err.Error()}
return c.JSON(e)
}

format := c.Query("timeFormat", "ISO")
if strings.ToLower(format) == "timestamp" {
resp := moon.SeachMoonDayRespTimestamp{
From: resp.From.Unix(),
To: resp.To.Unix(),
}
return c.JSON(resp)
} else if strings.ToLower(format) == "duration" {
resp := moon.SeachMoonDayRespTimestamp{
From: resp.From.Unix() - tGiven.Unix(),
To: resp.To.Unix() - tGiven.Unix(),
}
return c.JSON(resp)
} else if strings.ToLower(format) == "iso" {
return c.JSON(resp)
} else {
resp := moon.SeachMoonDayRespString{
From: resp.From.Format(format),
To: resp.To.Format(format),
}
return c.JSON(resp)
}
}
Loading