boilerplate code

This commit is contained in:
2025-10-09 05:20:06 +02:00
parent a7c436fe4c
commit b51f00e499
17 changed files with 500 additions and 17 deletions
+1
View File
@@ -0,0 +1 @@
package sensors
+110
View File
@@ -0,0 +1,110 @@
package sensors
import (
"encoding/json"
"nats-app/internal/iot"
"github.com/nats-io/nats.go"
)
const (
subjectSensorsRegister = "sensors.register"
subjectSensorsUpdate = "sensors.update"
subjectSensorsGet = "sensors.get"
subjectSensorsValuesGet = "sensors.values.get"
subjectSensorsList = "sensors.list"
)
type Handlers struct {
service *Service
*iot.IoTDevice
}
func NewHandlers(service *Service, iot *iot.IoTDevice) *Handlers {
return &Handlers{
service: service,
IoTDevice: iot,
}
}
func handleRequest[Req any, Res any](msg *nats.Msg, handler func(Req) (Res, error)) {
var req Req
if err := json.Unmarshal(msg.Data, &req); err != nil {
msg.Respond([]byte(`{"error":"invalid request"}`))
return
}
result, err := handler(req)
if err != nil {
msg.Respond([]byte(`{"error":"` + err.Error() + `"}`))
return
}
response, _ := json.Marshal(result)
msg.Respond(response)
}
func (h *Handlers) SetupEndpoints() *Handlers {
h.register()
h.update()
h.get()
h.getValues()
h.list()
return h
}
func (h *Handlers) register() {
h.NATS.Subscribe(subjectSensorsRegister, func(msg *nats.Msg) {
handleRequest(msg, func(req Sensor) (Sensor, error) {
// service layer
return req, nil
})
})
}
func (h *Handlers) update() {
h.NATS.Subscribe(subjectSensorsUpdate, func(msg *nats.Msg) {
handleRequest(msg, func(req Sensor) (Sensor, error) {
// service layer
return req, nil
})
})
}
func (h *Handlers) get() {
h.NATS.Subscribe(subjectSensorsGet, func(msg *nats.Msg) {
handleRequest(msg, func(req struct {
SensorID string `json:"sensor_id"`
}) (Sensor, error) {
// service layer
return Sensor{}, nil
})
})
}
func (h *Handlers) getValues() {
h.NATS.Subscribe(subjectSensorsValuesGet, func(msg *nats.Msg) {
handleRequest(msg, func(req struct {
SensorID string `json:"sensor_id"`
From string `json:"from"`
To string `json:"to"`
}) ([]SensorData, error) {
// service layer
return []SensorData{}, nil
})
})
}
func (h *Handlers) list() {
h.NATS.Subscribe(subjectSensorsList, func(msg *nats.Msg) {
handleRequest(msg, func(req struct{}) ([]Sensor, error) {
// service layer
return []Sensor{}, nil
})
})
}
+29
View File
@@ -0,0 +1,29 @@
package sensors
import "time"
type SType string
const (
Temperature SType = "temperature"
Humidity SType = "humidity"
CarbonDioxide SType = "carbon_dioxide"
Pressure SType = "pressure"
Proximity SType = "proximity"
Light SType = "light"
// and more...
)
type Sensor struct {
SensorID string `json:"sensor_id"`
SensorType SType `json:"sensor_type"`
SamplingInterval time.Duration `json:"sampling"`
ThresholdAbove float64 `json:"thresoldabove"`
ThresholdBelow float64 `json:"thresoldbelow"`
SensorData *[]SensorData `json:"sensor_data,omitempty"`
}
type SensorData struct {
Value float64 `json:"value"`
Timestamp time.Time `json:"timestamp"`
}
+150
View File
@@ -0,0 +1,150 @@
package sensors
import (
"log/slog"
"sync"
"time"
"github.com/jackc/pgx/v5/pgxpool"
)
type Repository interface {
RegisterSensor(s Sensor) error
UpdateSensorConfig(s Sensor) error
ReadSensor(id int) (Sensor, error)
ReadSensorValues(id int, from, to time.Time) ([]SensorData, error)
ReadAllSensors() ([]Sensor, error)
}
type pgxRepo struct {
pool *pgxpool.Pool
}
func newPGXRepo(pool *pgxpool.Pool) Repository {
return &pgxRepo{
pool: pool,
}
}
func (p *pgxRepo) ReadSensor(id int) (Sensor, error) {
panic("unimplemented")
}
func (p *pgxRepo) UpdateSensorConfig(s Sensor) error {
panic("unimplemented")
}
func (p *pgxRepo) RegisterSensor(s Sensor) error {
panic("unimplemented")
}
func (p *pgxRepo) ReadSensorValues(id int, from time.Time, to time.Time) ([]SensorData, error) {
panic("unimplemented")
}
func (p *pgxRepo) ReadAllSensors() ([]Sensor, error) {
panic("unimplemented")
}
type inMemory struct {
sensors map[string]*Sensor
mu *sync.Mutex
}
func newInMemoryRepo() Repository {
return &inMemory{
sensors: make(map[string]*Sensor),
}
}
func (i *inMemory) RegisterSensor(s Sensor) error {
panic("unimplemented")
}
func (i *inMemory) UpdateSensorConfig(s Sensor) error {
panic("unimplemented")
}
func (i *inMemory) ReadSensor(id int) (Sensor, error) {
panic("unimplemented")
}
func (i *inMemory) ReadSensorValues(id int, from time.Time, to time.Time) ([]SensorData, error) {
// holds only last 100 values for every sensor
panic("unimplemented")
}
func (i *inMemory) ReadAllSensors() ([]Sensor, error) {
panic("unimplemented")
}
type DecoratorRepo struct {
db Repository
memory Repository
}
func NewDecoratorRepo(pool *pgxpool.Pool) Repository {
db := newPGXRepo(pool)
memory := newInMemoryRepo()
sensors, err := db.ReadAllSensors()
if err != nil {
slog.Error("error warming up cache")
}
for _, s := range sensors {
_ = memory.RegisterSensor(s)
}
return &DecoratorRepo{
db: db,
memory: memory,
}
}
func (d *DecoratorRepo) RegisterSensor(s Sensor) error {
if err := d.db.RegisterSensor(s); err != nil {
return err
}
_ = d.memory.RegisterSensor(s)
return nil
}
func (d *DecoratorRepo) UpdateSensorConfig(s Sensor) error {
if err := d.db.UpdateSensorConfig(s); err != nil {
return err
}
_ = d.memory.UpdateSensorConfig(s)
return nil
}
func (d *DecoratorRepo) ReadSensor(id int) (Sensor, error) {
sensor, err := d.memory.ReadSensor(id)
if err == nil {
return sensor, nil
}
return d.db.ReadSensor(id)
}
func (d *DecoratorRepo) ReadSensorValues(id int, from, to time.Time) ([]SensorData, error) {
values, err := d.memory.ReadSensorValues(id, from, to)
if err == nil && len(values) > 0 {
return values, nil
}
return d.db.ReadSensorValues(id, from, to)
}
func (d *DecoratorRepo) ReadAllSensors() ([]Sensor, error) {
sensors, err := d.memory.ReadAllSensors()
if err == nil && len(sensors) > 0 {
return sensors, nil
}
return d.db.ReadAllSensors()
}
+11
View File
@@ -0,0 +1,11 @@
package sensors
type Service struct {
repo Repository
}
func NewService(repo Repository) *Service {
return &Service{
repo: repo,
}
}
+3
View File
@@ -0,0 +1,3 @@
package sensors
type Simulator struct{}