Implement HTTP timeout configurations and enhance API documentation
- Added optional HTTP server timeout configurations (`HNHMAP_READ_TIMEOUT`, `HNHMAP_WRITE_TIMEOUT`, `HNHMAP_IDLE_TIMEOUT`) to `.env.example` and updated the server initialization in `main.go` to utilize these settings. - Enhanced API documentation for the `rebuildZooms` endpoint to clarify its background processing and polling mechanism for status updates. - Updated `configuration.md` to include new timeout environment variables for better configuration guidance. - Improved error handling in the client for large request bodies, ensuring appropriate responses for oversized payloads.
This commit is contained in:
@@ -35,14 +35,23 @@ func NewExportService(st *store.Store, mapSvc *MapService) *ExportService {
|
||||
return &ExportService{st: st, mapSvc: mapSvc}
|
||||
}
|
||||
|
||||
// Export writes all map data as a ZIP archive to the given writer.
|
||||
func (s *ExportService) Export(ctx context.Context, w io.Writer) error {
|
||||
zw := zip.NewWriter(w)
|
||||
defer zw.Close()
|
||||
// exportEntry describes a single grid PNG to copy into the ZIP (collected inside a read-only View).
|
||||
type exportEntry struct {
|
||||
ZipPath string // e.g. "1/grid1.png"
|
||||
FilePath string // absolute path on disk
|
||||
}
|
||||
|
||||
return s.st.Update(ctx, func(tx *bbolt.Tx) error {
|
||||
maps := map[int]mapData{}
|
||||
gridMap := map[string]int{}
|
||||
// Export writes all map data as a ZIP archive to the given writer.
|
||||
// It uses a read-only View to collect data, then builds the ZIP outside the transaction
|
||||
// so that the write lock is not held during file I/O.
|
||||
func (s *ExportService) Export(ctx context.Context, w io.Writer) error {
|
||||
var maps map[int]mapData
|
||||
var gridMap map[string]int
|
||||
var filesToCopy []exportEntry
|
||||
|
||||
if err := s.st.View(ctx, func(tx *bbolt.Tx) error {
|
||||
maps = map[int]mapData{}
|
||||
gridMap = map[string]int{}
|
||||
|
||||
grids := tx.Bucket(store.BucketGrids)
|
||||
if grids == nil {
|
||||
@@ -54,6 +63,11 @@ func (s *ExportService) Export(ctx context.Context, w io.Writer) error {
|
||||
}
|
||||
|
||||
if err := grids.ForEach(func(k, v []byte) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
gd := app.GridData{}
|
||||
if err := json.Unmarshal(v, &gd); err != nil {
|
||||
return err
|
||||
@@ -84,17 +98,11 @@ func (s *ExportService) Export(ctx context.Context, w io.Writer) error {
|
||||
if err := json.Unmarshal(tdraw, &td); err != nil {
|
||||
return err
|
||||
}
|
||||
fw, err := zw.Create(fmt.Sprintf("%d/%s.png", gd.Map, gd.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.Open(filepath.Join(s.mapSvc.GridStorage(), td.File))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(fw, f)
|
||||
f.Close()
|
||||
return err
|
||||
filesToCopy = append(filesToCopy, exportEntry{
|
||||
ZipPath: fmt.Sprintf("%d/%s.png", gd.Map, gd.ID),
|
||||
FilePath: filepath.Join(s.mapSvc.GridStorage(), td.File),
|
||||
})
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -104,6 +112,11 @@ func (s *ExportService) Export(ctx context.Context, w io.Writer) error {
|
||||
markersgrid := markersb.Bucket(store.BucketMarkersGrid)
|
||||
if markersgrid != nil {
|
||||
markersgrid.ForEach(func(k, v []byte) error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
marker := app.Marker{}
|
||||
if json.Unmarshal(v, &marker) != nil {
|
||||
return nil
|
||||
@@ -115,16 +128,41 @@ func (s *ExportService) Export(ctx context.Context, w io.Writer) error {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for mapid, md := range maps {
|
||||
fw, err := zw.Create(fmt.Sprintf("%d/grids.json", mapid))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
json.NewEncoder(fw).Encode(md)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Build ZIP outside the transaction so the write lock is not held during file I/O.
|
||||
zw := zip.NewWriter(w)
|
||||
defer zw.Close()
|
||||
|
||||
for _, e := range filesToCopy {
|
||||
fw, err := zw.Create(e.ZipPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f, err := os.Open(e.FilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(fw, f)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for mapid, md := range maps {
|
||||
fw, err := zw.Create(fmt.Sprintf("%d/grids.json", mapid))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.NewEncoder(fw).Encode(md); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Merge imports map data from a ZIP file.
|
||||
|
||||
Reference in New Issue
Block a user