diff --git a/go.mod b/go.mod index ade9f29..bcf1753 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/protobuf v1.5.1 github.com/google/uuid v1.1.2 + github.com/hablullah/go-prayer v1.0.0 github.com/hailocab/go-geoindex v0.0.0-20160127134810-64631bfe9711 github.com/hashicorp/golang-lru v0.5.3 github.com/jackc/pgx/v4 v4.10.1 diff --git a/go.sum b/go.sum index 4f6fc98..1967164 100644 --- a/go.sum +++ b/go.sum @@ -202,6 +202,10 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= +github.com/hablullah/go-juliandays v1.0.0 h1:A8YM7wIj16SzlKT0SRJc9CD29iiaUzpBLzh5hr0/5p0= +github.com/hablullah/go-juliandays v1.0.0/go.mod h1:0JOYq4oFOuDja+oospuc61YoX+uNEn7Z6uHYTbBzdGc= +github.com/hablullah/go-prayer v1.0.0 h1:w5Py1QUgxHl1x20HDwcF+uZsipPxJrnmeoJFy+KcZrY= +github.com/hablullah/go-prayer v1.0.0/go.mod h1:/frx38qd63RPtqVx8RnnVTUlhgngB0Ral4liRUMOnxU= github.com/hailocab/go-geoindex v0.0.0-20160127134810-64631bfe9711 h1:Oi8hPOZX0gaM2sPVXse2bMpfOjP47a7O61YuB6Z4sGk= github.com/hailocab/go-geoindex v0.0.0-20160127134810-64631bfe9711/go.mod h1:+v2qJ3UZe4q2GfgZO4od004F/cMgJbmPSs7dD/ZMUkY= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= diff --git a/prayer/.gitignore b/prayer/.gitignore new file mode 100644 index 0000000..8af0f91 --- /dev/null +++ b/prayer/.gitignore @@ -0,0 +1,2 @@ + +prayer diff --git a/prayer/Dockerfile b/prayer/Dockerfile new file mode 100644 index 0000000..e873ec4 --- /dev/null +++ b/prayer/Dockerfile @@ -0,0 +1,3 @@ +FROM alpine +ADD prayer /prayer +ENTRYPOINT [ "/prayer" ] diff --git a/prayer/Makefile b/prayer/Makefile new file mode 100644 index 0000000..228499e --- /dev/null +++ b/prayer/Makefile @@ -0,0 +1,28 @@ + +GOPATH:=$(shell go env GOPATH) +.PHONY: init +init: + go get -u github.com/golang/protobuf/proto + go get -u github.com/golang/protobuf/protoc-gen-go + go get github.com/micro/micro/v3/cmd/protoc-gen-micro + go get github.com/micro/micro/v3/cmd/protoc-gen-openapi + +.PHONY: api +api: + protoc --openapi_out=. --proto_path=. proto/prayer.proto + +.PHONY: proto +proto: + protoc --proto_path=. --micro_out=. --go_out=:. proto/prayer.proto + +.PHONY: build +build: + go build -o prayer *.go + +.PHONY: test +test: + go test -v ./... -cover + +.PHONY: docker +docker: + docker build . -t prayer:latest diff --git a/prayer/README.md b/prayer/README.md new file mode 100644 index 0000000..3baef37 --- /dev/null +++ b/prayer/README.md @@ -0,0 +1,8 @@ +Islamic prayer times + +# Prayer Service + +Prayer (salah) times for the religion of Islam. The daily obligatory prayers collectively form the second of the five pillars +in Islam, observed five times every day at prescribed times. These are Fajr (observed at dawn), Zuhr prayer (observed at noon), Asr (observed late +in the afternoon), Maghrib (observed at dusk), and Isha (observed after sunset). + diff --git a/prayer/generate.go b/prayer/generate.go new file mode 100644 index 0000000..7d9db91 --- /dev/null +++ b/prayer/generate.go @@ -0,0 +1,3 @@ +package main + +//go:generate make proto diff --git a/prayer/handler/prayer.go b/prayer/handler/prayer.go new file mode 100644 index 0000000..6bf6b10 --- /dev/null +++ b/prayer/handler/prayer.go @@ -0,0 +1,115 @@ +package handler + +import ( + "context" + "fmt" + "time" + + "github.com/hablullah/go-prayer" + "github.com/micro/micro/v3/service/client" + "github.com/micro/micro/v3/service/errors" + geocode "github.com/micro/services/geocoding/proto" + pb "github.com/micro/services/prayer/proto" + timepb "github.com/micro/services/time/proto" +) + +type Prayer struct{ + Geocode geocode.GeocodingService + Time timepb.TimeService +} + +func New(c client.Client) *Prayer { + return &Prayer{ + Geocode: geocode.NewGeocodingService("geocoding", c), + Time: timepb.NewTimeService("time", c), + } +} + +func (p *Prayer) Times(ctx context.Context, req *pb.TimesRequest, rsp *pb.TimesResponse) error { + // geocode the location + if len(req.Location) == 0 && req.Latitude == 0.0 && req.Longitude == 0.0 { + return errors.BadRequest("prayer.times", "missing location") + } + + latitude := req.Latitude + longitude := req.Longitude + + // get lat/lng if location is specified + if len(req.Location) > 0 { + resp, err := p.Geocode.Lookup(ctx, &geocode.LookupRequest{ + Address: req.Location, + }) + if err != nil { + return errors.InternalServerError("prayer.times", "failed to lookup location") + } + latitude = resp.Location.Latitude + longitude = resp.Location.Longitude + } + + if latitude == 0.0 && longitude == 0.0 { + return errors.BadRequest("prayer.times", "missing location") + } + + // get the timezone + resp, err := p.Time.Zone(ctx, &timepb.ZoneRequest{ + Location: fmt.Sprintf("%v,%v", latitude, longitude), + }) + if err != nil { + return errors.InternalServerError("prayer.times", "failed to lookup timezone") + } + + cfg := prayer.Config{ + Latitude: latitude, + Longitude: longitude, + CalculationMethod: prayer.Kemenag, + AsrConvention: prayer.Shafii, + PreciseToSeconds: false, + } + + // current date + date := time.Now() + + // if date is specified then change it + if len(req.Date) > 0 { + d, err := time.Parse("2006-01-02", req.Date) + if err == nil { + date = d + } + } + + if req.Days == 0 { + req.Days = 1 + } + + // set time zone + zone, _ := time.LoadLocation(resp.Timezone) + date = date.In(zone) + + rsp.Date = date.Format("2006-01-02") + rsp.Days = req.Days + rsp.Location = req.Location + rsp.Latitude = latitude + rsp.Longitude = longitude + + for i := 0; i < int(req.Days); i++ { + times, err := prayer.Calculate(cfg, date) + if err != nil { + return errors.InternalServerError("prayer.times", "failed to retrieve prayer times") + } + + rsp.Times = append(rsp.Times, &pb.PrayerTime{ + Date: date.Format("2006-01-02"), + Fajr: times.Fajr.Format("15:04"), + Sunrise: times.Sunrise.Format("15:04"), + Zuhr: times.Zuhr.Format("15:04"), + Asr: times.Asr.Format("15:04"), + Maghrib: times.Maghrib.Format("15:04"), + Isha: times.Isha.Format("15:04"), + }) + + // add a day + date = date.AddDate(0, 0, 1) + } + + return nil +} diff --git a/prayer/main.go b/prayer/main.go new file mode 100644 index 0000000..f62bae5 --- /dev/null +++ b/prayer/main.go @@ -0,0 +1,24 @@ +package main + +import ( + "github.com/micro/micro/v3/service" + "github.com/micro/micro/v3/service/logger" + "github.com/micro/services/prayer/handler" + pb "github.com/micro/services/prayer/proto" +) + +func main() { + // Create service + srv := service.New( + service.Name("prayer"), + service.Version("latest"), + ) + + // Register handler + pb.RegisterPrayerHandler(srv.Server(), handler.New(srv.Client())) + + // Run service + if err := srv.Run(); err != nil { + logger.Fatal(err) + } +} diff --git a/prayer/micro.mu b/prayer/micro.mu new file mode 100644 index 0000000..b5a4798 --- /dev/null +++ b/prayer/micro.mu @@ -0,0 +1 @@ +service prayer diff --git a/prayer/proto/prayer.pb.go b/prayer/proto/prayer.pb.go new file mode 100644 index 0000000..f613ad0 --- /dev/null +++ b/prayer/proto/prayer.pb.go @@ -0,0 +1,437 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.15.6 +// source: proto/prayer.proto + +package prayer + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type PrayerTime struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // date for prayer times in YYYY-MM-DD format + Date string `protobuf:"bytes,1,opt,name=date,proto3" json:"date,omitempty"` + // fajr time + Fajr string `protobuf:"bytes,2,opt,name=fajr,proto3" json:"fajr,omitempty"` + // time of sunrise + Sunrise string `protobuf:"bytes,3,opt,name=sunrise,proto3" json:"sunrise,omitempty"` + // zuhr time + Zuhr string `protobuf:"bytes,4,opt,name=zuhr,proto3" json:"zuhr,omitempty"` + // asr time + Asr string `protobuf:"bytes,5,opt,name=asr,proto3" json:"asr,omitempty"` + // maghrib time + Maghrib string `protobuf:"bytes,6,opt,name=maghrib,proto3" json:"maghrib,omitempty"` + // isha time + Isha string `protobuf:"bytes,7,opt,name=isha,proto3" json:"isha,omitempty"` +} + +func (x *PrayerTime) Reset() { + *x = PrayerTime{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_prayer_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PrayerTime) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PrayerTime) ProtoMessage() {} + +func (x *PrayerTime) ProtoReflect() protoreflect.Message { + mi := &file_proto_prayer_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PrayerTime.ProtoReflect.Descriptor instead. +func (*PrayerTime) Descriptor() ([]byte, []int) { + return file_proto_prayer_proto_rawDescGZIP(), []int{0} +} + +func (x *PrayerTime) GetDate() string { + if x != nil { + return x.Date + } + return "" +} + +func (x *PrayerTime) GetFajr() string { + if x != nil { + return x.Fajr + } + return "" +} + +func (x *PrayerTime) GetSunrise() string { + if x != nil { + return x.Sunrise + } + return "" +} + +func (x *PrayerTime) GetZuhr() string { + if x != nil { + return x.Zuhr + } + return "" +} + +func (x *PrayerTime) GetAsr() string { + if x != nil { + return x.Asr + } + return "" +} + +func (x *PrayerTime) GetMaghrib() string { + if x != nil { + return x.Maghrib + } + return "" +} + +func (x *PrayerTime) GetIsha() string { + if x != nil { + return x.Isha + } + return "" +} + +type TimesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // optional date in YYYY-MM-DD format, otherwise uses today + Date string `protobuf:"bytes,1,opt,name=date,proto3" json:"date,omitempty"` + // number of days to request times for + Days int32 `protobuf:"varint,2,opt,name=days,proto3" json:"days,omitempty"` + // location to retrieve prayer times for. + // this can be a specific address, city, etc + Location string `protobuf:"bytes,3,opt,name=location,proto3" json:"location,omitempty"` + // optional latitude used in place of location + Latitude float64 `protobuf:"fixed64,4,opt,name=latitude,proto3" json:"latitude,omitempty"` + // optional longitude used in place of location + Longitude float64 `protobuf:"fixed64,5,opt,name=longitude,proto3" json:"longitude,omitempty"` +} + +func (x *TimesRequest) Reset() { + *x = TimesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_prayer_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TimesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TimesRequest) ProtoMessage() {} + +func (x *TimesRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_prayer_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TimesRequest.ProtoReflect.Descriptor instead. +func (*TimesRequest) Descriptor() ([]byte, []int) { + return file_proto_prayer_proto_rawDescGZIP(), []int{1} +} + +func (x *TimesRequest) GetDate() string { + if x != nil { + return x.Date + } + return "" +} + +func (x *TimesRequest) GetDays() int32 { + if x != nil { + return x.Days + } + return 0 +} + +func (x *TimesRequest) GetLocation() string { + if x != nil { + return x.Location + } + return "" +} + +func (x *TimesRequest) GetLatitude() float64 { + if x != nil { + return x.Latitude + } + return 0 +} + +func (x *TimesRequest) GetLongitude() float64 { + if x != nil { + return x.Longitude + } + return 0 +} + +type TimesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // date of request + Date string `protobuf:"bytes,1,opt,name=date,proto3" json:"date,omitempty"` + // number of days + Days int32 `protobuf:"varint,2,opt,name=days,proto3" json:"days,omitempty"` + // location for the request + Location string `protobuf:"bytes,3,opt,name=location,proto3" json:"location,omitempty"` + // latitude of location + Latitude float64 `protobuf:"fixed64,4,opt,name=latitude,proto3" json:"latitude,omitempty"` + // longitude of location + Longitude float64 `protobuf:"fixed64,5,opt,name=longitude,proto3" json:"longitude,omitempty"` + // prayer times for the given location + Times []*PrayerTime `protobuf:"bytes,6,rep,name=times,proto3" json:"times,omitempty"` +} + +func (x *TimesResponse) Reset() { + *x = TimesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_prayer_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TimesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TimesResponse) ProtoMessage() {} + +func (x *TimesResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_prayer_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TimesResponse.ProtoReflect.Descriptor instead. +func (*TimesResponse) Descriptor() ([]byte, []int) { + return file_proto_prayer_proto_rawDescGZIP(), []int{2} +} + +func (x *TimesResponse) GetDate() string { + if x != nil { + return x.Date + } + return "" +} + +func (x *TimesResponse) GetDays() int32 { + if x != nil { + return x.Days + } + return 0 +} + +func (x *TimesResponse) GetLocation() string { + if x != nil { + return x.Location + } + return "" +} + +func (x *TimesResponse) GetLatitude() float64 { + if x != nil { + return x.Latitude + } + return 0 +} + +func (x *TimesResponse) GetLongitude() float64 { + if x != nil { + return x.Longitude + } + return 0 +} + +func (x *TimesResponse) GetTimes() []*PrayerTime { + if x != nil { + return x.Times + } + return nil +} + +var File_proto_prayer_proto protoreflect.FileDescriptor + +var file_proto_prayer_proto_rawDesc = []byte{ + 0x0a, 0x12, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x61, 0x79, 0x65, 0x72, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x70, 0x72, 0x61, 0x79, 0x65, 0x72, 0x22, 0xa2, 0x01, 0x0a, + 0x0a, 0x50, 0x72, 0x61, 0x79, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, + 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x66, 0x61, 0x6a, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, + 0x61, 0x6a, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x6e, 0x72, 0x69, 0x73, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x75, 0x6e, 0x72, 0x69, 0x73, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x7a, 0x75, 0x68, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x7a, 0x75, 0x68, + 0x72, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x61, 0x73, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x61, 0x67, 0x68, 0x72, 0x69, 0x62, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x61, 0x67, 0x68, 0x72, 0x69, 0x62, 0x12, 0x12, 0x0a, + 0x04, 0x69, 0x73, 0x68, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x73, 0x68, + 0x61, 0x22, 0x8c, 0x01, 0x0a, 0x0c, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x79, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x61, 0x79, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, + 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, + 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, + 0x22, 0xb7, 0x01, 0x0a, 0x0d, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x79, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x64, 0x61, 0x79, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, + 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, + 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, + 0x12, 0x28, 0x0a, 0x05, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x12, 0x2e, 0x70, 0x72, 0x61, 0x79, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x61, 0x79, 0x65, 0x72, 0x54, + 0x69, 0x6d, 0x65, 0x52, 0x05, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x32, 0x40, 0x0a, 0x06, 0x50, 0x72, + 0x61, 0x79, 0x65, 0x72, 0x12, 0x36, 0x0a, 0x05, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x12, 0x14, 0x2e, + 0x70, 0x72, 0x61, 0x79, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x72, 0x61, 0x79, 0x65, 0x72, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x10, 0x5a, 0x0e, + 0x2e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3b, 0x70, 0x72, 0x61, 0x79, 0x65, 0x72, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_proto_prayer_proto_rawDescOnce sync.Once + file_proto_prayer_proto_rawDescData = file_proto_prayer_proto_rawDesc +) + +func file_proto_prayer_proto_rawDescGZIP() []byte { + file_proto_prayer_proto_rawDescOnce.Do(func() { + file_proto_prayer_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_prayer_proto_rawDescData) + }) + return file_proto_prayer_proto_rawDescData +} + +var file_proto_prayer_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_proto_prayer_proto_goTypes = []interface{}{ + (*PrayerTime)(nil), // 0: prayer.PrayerTime + (*TimesRequest)(nil), // 1: prayer.TimesRequest + (*TimesResponse)(nil), // 2: prayer.TimesResponse +} +var file_proto_prayer_proto_depIdxs = []int32{ + 0, // 0: prayer.TimesResponse.times:type_name -> prayer.PrayerTime + 1, // 1: prayer.Prayer.Times:input_type -> prayer.TimesRequest + 2, // 2: prayer.Prayer.Times:output_type -> prayer.TimesResponse + 2, // [2:3] is the sub-list for method output_type + 1, // [1:2] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_proto_prayer_proto_init() } +func file_proto_prayer_proto_init() { + if File_proto_prayer_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_proto_prayer_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PrayerTime); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_prayer_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TimesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_prayer_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TimesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_proto_prayer_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_proto_prayer_proto_goTypes, + DependencyIndexes: file_proto_prayer_proto_depIdxs, + MessageInfos: file_proto_prayer_proto_msgTypes, + }.Build() + File_proto_prayer_proto = out.File + file_proto_prayer_proto_rawDesc = nil + file_proto_prayer_proto_goTypes = nil + file_proto_prayer_proto_depIdxs = nil +} diff --git a/prayer/proto/prayer.pb.micro.go b/prayer/proto/prayer.pb.micro.go new file mode 100644 index 0000000..c867ec7 --- /dev/null +++ b/prayer/proto/prayer.pb.micro.go @@ -0,0 +1,93 @@ +// Code generated by protoc-gen-micro. DO NOT EDIT. +// source: proto/prayer.proto + +package prayer + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +import ( + context "context" + api "github.com/micro/micro/v3/service/api" + client "github.com/micro/micro/v3/service/client" + server "github.com/micro/micro/v3/service/server" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// Reference imports to suppress errors if they are not otherwise used. +var _ api.Endpoint +var _ context.Context +var _ client.Option +var _ server.Option + +// Api Endpoints for Prayer service + +func NewPrayerEndpoints() []*api.Endpoint { + return []*api.Endpoint{} +} + +// Client API for Prayer service + +type PrayerService interface { + Times(ctx context.Context, in *TimesRequest, opts ...client.CallOption) (*TimesResponse, error) +} + +type prayerService struct { + c client.Client + name string +} + +func NewPrayerService(name string, c client.Client) PrayerService { + return &prayerService{ + c: c, + name: name, + } +} + +func (c *prayerService) Times(ctx context.Context, in *TimesRequest, opts ...client.CallOption) (*TimesResponse, error) { + req := c.c.NewRequest(c.name, "Prayer.Times", in) + out := new(TimesResponse) + err := c.c.Call(ctx, req, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for Prayer service + +type PrayerHandler interface { + Times(context.Context, *TimesRequest, *TimesResponse) error +} + +func RegisterPrayerHandler(s server.Server, hdlr PrayerHandler, opts ...server.HandlerOption) error { + type prayer interface { + Times(ctx context.Context, in *TimesRequest, out *TimesResponse) error + } + type Prayer struct { + prayer + } + h := &prayerHandler{hdlr} + return s.Handle(s.NewHandler(&Prayer{h}, opts...)) +} + +type prayerHandler struct { + PrayerHandler +} + +func (h *prayerHandler) Times(ctx context.Context, in *TimesRequest, out *TimesResponse) error { + return h.PrayerHandler.Times(ctx, in, out) +} diff --git a/prayer/proto/prayer.proto b/prayer/proto/prayer.proto new file mode 100644 index 0000000..3c83a74 --- /dev/null +++ b/prayer/proto/prayer.proto @@ -0,0 +1,55 @@ +syntax = "proto3"; + +package prayer; + +option go_package = "./proto;prayer"; + +service Prayer { + rpc Times(TimesRequest) returns (TimesResponse) {} +} + +message PrayerTime { + // date for prayer times in YYYY-MM-DD format + string date = 1; + // fajr time + string fajr = 2; + // time of sunrise + string sunrise = 3; + // zuhr time + string zuhr = 4; + // asr time + string asr = 5; + // maghrib time + string maghrib = 6; + // isha time + string isha = 7; +} + +message TimesRequest { + // optional date in YYYY-MM-DD format, otherwise uses today + string date = 1; + // number of days to request times for + int32 days = 2; + // location to retrieve prayer times for. + // this can be a specific address, city, etc + string location = 3; + // optional latitude used in place of location + double latitude = 4; + // optional longitude used in place of location + double longitude = 5; +} + +message TimesResponse { + // date of request + string date = 1; + // number of days + int32 days = 2; + // location for the request + string location = 3; + // latitude of location + double latitude = 4; + // longitude of location + double longitude = 5; + // prayer times for the given location + repeated PrayerTime times = 6; +} diff --git a/prayer/publicapi.json b/prayer/publicapi.json new file mode 100644 index 0000000..4a98dec --- /dev/null +++ b/prayer/publicapi.json @@ -0,0 +1,5 @@ +{ + "name": "prayer", + "icon": "🙏", + "category": "religion" +}