mirror of
https://github.com/Cernobor/oko-server.git
synced 2025-02-24 08:27:17 +00:00
Compare commits
7 Commits
7c8a430f49
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e713ae8da | |||
| 8440e3b7d7 | |||
| 63e79c657c | |||
| f168a5966b | |||
| d25e58905f | |||
| 90f8fef40a | |||
| f9850c3264 |
@@ -0,0 +1,107 @@
|
|||||||
|
<p align="center">
|
||||||
|
<a href="" rel="noopener">
|
||||||
|
<img src="https://raw.githubusercontent.com/Cernobor/oko-app/master/assets/splash.png" alt="Project logo" style="background: #153d24;"></a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 align="center">Organizátorské Kartografické OKO - server</h3>
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
[]()
|
||||||
|
[](https://github.com/Cernobor/oko-server/issues)
|
||||||
|
[](https://github.com/Cernobor/oko-server/pulls)
|
||||||
|
<!-- [](/LICENSE) -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Table of Contents
|
||||||
|
|
||||||
|
- [About](#about)
|
||||||
|
- [Building](#building)
|
||||||
|
- [Usage](#usage)
|
||||||
|
- [Built Using](#built_using)
|
||||||
|
- [Authors](#authors)
|
||||||
|
- [Acknowledgments](#acknowledgement)
|
||||||
|
|
||||||
|
## 🧐 About <a name = "about"></a>
|
||||||
|
|
||||||
|
Central server for the [OKO](https://github.com/Cernobor/oko-app) app.
|
||||||
|
Manges users, provides map tiles and the whole map tile pack, receives geo features submitted by users and serves them back.
|
||||||
|
|
||||||
|
## 🏗 Building <a name = "building"></a>
|
||||||
|
|
||||||
|
The only requirement to build the server is [go](https://go.dev).
|
||||||
|
|
||||||
|
In the root of the project, run
|
||||||
|
|
||||||
|
```
|
||||||
|
go build
|
||||||
|
```
|
||||||
|
|
||||||
|
which will produce the executable ``oko-server`` which you can just run (see [Usage](#usage)).
|
||||||
|
|
||||||
|
## 🎈 Usage <a name="usage"></a>
|
||||||
|
|
||||||
|
### Using docker
|
||||||
|
|
||||||
|
Dockerfile is included, therefore to build the docker image, all that is needed to do is to run
|
||||||
|
|
||||||
|
```
|
||||||
|
docker build -t name:tag /path/to/the/root/of/the/repository
|
||||||
|
```
|
||||||
|
or, if you have no local changes, you can build the image even without cloning the repository at all
|
||||||
|
```
|
||||||
|
docker build -t name:tag https://github.com/Cernobor/oko-server.git
|
||||||
|
```
|
||||||
|
|
||||||
|
The image can then be run using the ``name:tag`` that you have given in the previous step.
|
||||||
|
Volume ``/data`` is available to share data between the host and the container.
|
||||||
|
|
||||||
|
```
|
||||||
|
docker run -v /path/to/data:/data name:tag [options...]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Without docker
|
||||||
|
|
||||||
|
Just run the previously built (see [Building](#building)) executable
|
||||||
|
```
|
||||||
|
/path/to/oko-server [options...]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
The server is configurable via a set of options, some of which are required.
|
||||||
|
The table of options follows:
|
||||||
|
|
||||||
|
| option | description |
|
||||||
|
| ------ | ----------- |
|
||||||
|
| ``-tilepack <path>`` | **Required.** File that will be sent to clients when they request a tile pack, also used to serve tiles in online mode. |
|
||||||
|
| ``-port <port>`` | Port where the server will listen. Default is ``8080``. |
|
||||||
|
| ``-dbfile <path>`` | Path to the sqlite3 database file used for data storage. Will be created, if it does not exist upons startup. Default is ``./data.sqlite3``. |
|
||||||
|
| ``-min-zoom <int>`` | Minimum supported zoom. Clients will receive this value during handshake. Default is ``1``. |
|
||||||
|
| ``-default-center-lat <float>`` | Latitude of the default map center, formatted as a floating point number of degrees. Clients will receive this value during handhake. Default is ``0``. |
|
||||||
|
| ``-default-center-lng <float>`` | Longitude of the default map center, formatted as a floating point number of degrees. Clients will receive this value during handhake. Default is ``0``. |
|
||||||
|
| ``-max-photo-width <int>`` | Maximum width of stored pohotos. Uploaded photos exceeding this width will be rescaled to fit (keeping aspect ratio). If ``0``, no scaling will be done. Default is ``0``. |
|
||||||
|
| ``-max-photo-height <int>`` | Maximum height of stored pohotos. Uploaded photos exceeding this height will be rescaled to fit (keeping aspect ratio). If ``0``, no scaling will be done. Default is ``0``. |
|
||||||
|
| ``-photo-quality <int>`` | JPEG photo quality. Photos are reencoded to JPEG with this quality setting when uploaded. Default is ``90``. |
|
||||||
|
| ``-debug`` | If specified, logging level will be set do debug instead of info. w
|
||||||
|
|
||||||
|
## ⛏️ Built Using <a name = "built_using"></a>
|
||||||
|
|
||||||
|
- [Go](https://go.dev/) - Programming language
|
||||||
|
- [Gin](https://gin-gonic.com/) - HTTP handler
|
||||||
|
- [SQLite](https://www.sqlite.org/) - Database
|
||||||
|
- [mbtileserver](https://github.com/consbio/mbtileserver) - MBTiles tile server
|
||||||
|
|
||||||
|
## ✍️ Authors <a name = "authors"></a>
|
||||||
|
|
||||||
|
- [@zegkljan](https://github.com/zegkljan) - Idea & Initial work
|
||||||
|
- [@0x416E64](https://github.com/0x416E64) - Docker and deployment tweaks
|
||||||
|
|
||||||
|
See also the list of [contributors](https://github.com/Cernobor/oko-server/contributors) who participated in this project.
|
||||||
|
|
||||||
|
## 🎉 Acknowledgements <a name = "acknowledgement"></a>
|
||||||
|
|
||||||
|
- Hat tip to anyone whose code was used
|
||||||
+878
@@ -0,0 +1,878 @@
|
|||||||
|
{
|
||||||
|
"openapi": "3.0.3",
|
||||||
|
"info": {
|
||||||
|
"title": "OKO server API",
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "http://localhost:8080/",
|
||||||
|
"description": "Local testing."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"components": {
|
||||||
|
"securitySchemes": {},
|
||||||
|
"schemas": {
|
||||||
|
"Error": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"message"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"AppVersionInfo": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"address": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "URL from which the app of this version can be downloaded."
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Version of the app in the format 'major.minor.patch[-prerelease][+metadata]' (without quotes)."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["address", "version"],
|
||||||
|
"description": "Info about an available app."
|
||||||
|
},
|
||||||
|
"HandshakeChallenge": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of the user."
|
||||||
|
},
|
||||||
|
"exists": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Indicates to the server whether this user is supposed to already exist and therefore should only bind to this existing user."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["name"],
|
||||||
|
"description": "Data for handshake initiation."
|
||||||
|
},
|
||||||
|
"HandshakeResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "User ID assigned by the server."
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of the user as requested by the client."
|
||||||
|
},
|
||||||
|
"map_info": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"map_pack_path": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "URL path to the map pack."
|
||||||
|
},
|
||||||
|
"map_pack_size": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Size of the map pack in bytes."
|
||||||
|
},
|
||||||
|
"tile_path_template": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Template of the URL path to the map tiles."
|
||||||
|
},
|
||||||
|
"min_zoom": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Minimum zoom supported by the server/map pack."
|
||||||
|
},
|
||||||
|
"default_center": {
|
||||||
|
"$ref": "#/components/schemas/Coords"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["map_pack_path", "map_pack_size", "tile_path_template", "min_zoom", "default_center"],
|
||||||
|
"description": "Info about map settings."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["id", "name", "map_info"],
|
||||||
|
"description": "Response to successful handshake. Tells the client how to set itself up."
|
||||||
|
},
|
||||||
|
"Coords": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"lat": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Latitude (north-south coordinate). Positive number indicates north, negative south."
|
||||||
|
},
|
||||||
|
"lng": {
|
||||||
|
"type": "number",
|
||||||
|
"description": "Longitude (east-west coordinate). Positive number indicates east, negative west."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["lat", "lng"],
|
||||||
|
"description": "WGS84 coordinates - latitude and longitude."
|
||||||
|
},
|
||||||
|
"User": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "User ID."
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "User name."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["id", "name"],
|
||||||
|
"description": "A user in the system."
|
||||||
|
},
|
||||||
|
"UserInfo": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "User ID."
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "User name."
|
||||||
|
},
|
||||||
|
"app_version": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Version of the app last used by the user."
|
||||||
|
},
|
||||||
|
"last_seen_time": {
|
||||||
|
"anyOf": [{"$ref": "#/components/schemas/LocalDateTime"}],
|
||||||
|
"description": "Time of last contact (any) with the server."
|
||||||
|
},
|
||||||
|
"last_upload_time": {
|
||||||
|
"anyOf": [{"$ref": "#/components/schemas/LocalDateTime"}],
|
||||||
|
"description": "Time of last data upload."
|
||||||
|
},
|
||||||
|
"last_download_time": {
|
||||||
|
"anyOf": [{"$ref": "#/components/schemas/LocalDateTime"}],
|
||||||
|
"description": "Time of last data download."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["id", "name", "app_version", "last_seen_time", "last_upload_time", "last_download_time"],
|
||||||
|
"description": "Extended info about a user."
|
||||||
|
},
|
||||||
|
"Feature": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "ID of the feature."
|
||||||
|
},
|
||||||
|
"owner_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "ID of the user owning this feature."
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of the feature."
|
||||||
|
},
|
||||||
|
"deadline": {
|
||||||
|
"allOf": [{"$ref": "#/components/schemas/LocalDateTime"}],
|
||||||
|
"description": "Time at which the feature should be deleted."
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": true,
|
||||||
|
"description": "Any extra data associated with the feature."
|
||||||
|
},
|
||||||
|
"geometry": {
|
||||||
|
"allOf": [{"$ref": "https://geojson.org/schema/Geometry.json"}],
|
||||||
|
"description": "Geometry describing this feature."
|
||||||
|
},
|
||||||
|
"photo_ids": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"description": "IDs of photos associated with this feature."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["id", "owner_id", "name", "geometry"]
|
||||||
|
},
|
||||||
|
"PhotoMetadata": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"content_type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "MIME type of the file containing the photo."
|
||||||
|
},
|
||||||
|
"thumbnail_content_type": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "MIME type of the file containing the thumbnail of the photo."
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Size of the file containing the photo in bytes."
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "ID of the photo."
|
||||||
|
},
|
||||||
|
"thumbnail_filename": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Name of the file containing the thumbnail of the photo."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["content_type", "thumbnail_content_type", "size", "id", "thumbnail_filename"],
|
||||||
|
"description": "Metadata about a photo."
|
||||||
|
},
|
||||||
|
"Proposal": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"owner_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "ID of the owner (author) of the proposal."
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Description of what should the system do better/different/what it does not do now."
|
||||||
|
},
|
||||||
|
"how": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "How should the system behave to meet this demand."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["owner_id", "description", "how"],
|
||||||
|
"description": "A proposal for improvement of the system."
|
||||||
|
},
|
||||||
|
"Data": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"users": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/User"
|
||||||
|
},
|
||||||
|
"description": "Users present in the system."
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Feature"
|
||||||
|
},
|
||||||
|
"description": "Features present in the system."
|
||||||
|
},
|
||||||
|
"photo_metadata": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"$ref": "#/components/schemas/PhotoMetadata"
|
||||||
|
},
|
||||||
|
"description": "Mapping from photo ID to metadata describing that photo."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["users", "features"],
|
||||||
|
"description": "Data about users and features."
|
||||||
|
},
|
||||||
|
"Update": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"create": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Feature"
|
||||||
|
},
|
||||||
|
"description": "Newly created features. The IDs of these features are considered 'local' to this set of features and must be unique among them."
|
||||||
|
},
|
||||||
|
"created_photos": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "Mapping from ID of a feature defined in 'created' to a multipart/form-data filed name of a photo associated with that feature."
|
||||||
|
},
|
||||||
|
"add_photos": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "Mapping from ID of an already existing feature to a multipart/form-data filed name of a photo that is to be added to that feature."
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Feature"
|
||||||
|
},
|
||||||
|
"description": "Features to be updated. They are matched by their ID."
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"description": "IDs of features that are to be deleted."
|
||||||
|
},
|
||||||
|
"delete_photos": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"description": "IDs of photos that are to be deleted."
|
||||||
|
},
|
||||||
|
"proposals": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Proposal"
|
||||||
|
},
|
||||||
|
"description": "New proposals for improvement of the system."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Data update to server."
|
||||||
|
},
|
||||||
|
"LocalDateTime": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time",
|
||||||
|
"example": "2020-05-13T17:26:57.719+02:00"
|
||||||
|
},
|
||||||
|
"BuildInfo": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"version_hash": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Commit ID (hash)."
|
||||||
|
},
|
||||||
|
"build_time": {
|
||||||
|
"anyOf": [{"$ref": "#/components/schemas/LocalDateTime"}],
|
||||||
|
"description": "Build time."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["version_hash", "build_time"],
|
||||||
|
"description": "Server build info."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"UserID": {
|
||||||
|
"in": "header",
|
||||||
|
"name": "X-User-ID",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"required": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [],
|
||||||
|
"paths": {
|
||||||
|
"/ping" : {
|
||||||
|
"parameters": [{"$ref": "#/components/parameters/UserID"}],
|
||||||
|
"get": {
|
||||||
|
"operationId": "ping",
|
||||||
|
"tags": ["app"],
|
||||||
|
"summary": "Checks the server liveness and provides info about (newer) app versions.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Server is alive, and there is a newer version of the app available. The response contains the app info.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/AppVersionInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"204": {
|
||||||
|
"description": "Server is alive, and there is no newer version of the app."
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "App version info in User-Agent header is malformed."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/handshake": {
|
||||||
|
"parameters": [{"$ref": "#/components/parameters/UserID"}],
|
||||||
|
"post": {
|
||||||
|
"operationId": "handshake",
|
||||||
|
"tags": ["app"],
|
||||||
|
"summary": "Performs pairing of the client with the server.",
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"description": "Handshake challenge.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HandshakeChallenge"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Handshake successful, response body contains the handshake response.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HandshakeResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Malformed handshake challenge."
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Attempted to associate ('exists' was set to true) with a reserved (system) user."
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Attempted to associate ('exists' was set to true) with a non-existing user."
|
||||||
|
},
|
||||||
|
"409": {
|
||||||
|
"description": "Attempted to create ('exists' was not set or set to false) an already existing user."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/data": {
|
||||||
|
"parameters": [{"$ref": "#/components/parameters/UserID"}],
|
||||||
|
"get": {
|
||||||
|
"operationId": "getData",
|
||||||
|
"tags": ["app"],
|
||||||
|
"summary": "Retrieves the data about users and features from the server.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The data, either by themselves (application/json), or with the photos associated with the features (application/zip). Determined by the Accept header.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Data"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application/zip": {
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "binary",
|
||||||
|
"description": "A zip-file containing all the data. In the zip file, there is a file data.json, which contains the feature data in the same format as for the applicaion/json response. The photos are stored in sibling files with name patterns img{id} and thumb_img{id} for the photo and its thumbnail respectively, where {id} is the ID of the photo corresponding to the photo IDs described in the feature data."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"406": {
|
||||||
|
"description": "Unsupported Accept header value."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"operationId": "postData",
|
||||||
|
"tags": ["app"],
|
||||||
|
"summary": "Uploads new data to the server.",
|
||||||
|
"description": "The update process goes through these steps:\n\n 1. all created features (if any) are added to the system\n 2. new photos (if any) for both the new and existing features are saved\n 3. the features that should be updated (if any) are updated \n 4. the features to be deleted (if any) are deleted\n 5. the photos to be deleted (if any) are deleted\n 6. the proposals (if any) are saved\n\nThe whole upload process is atomic, i.e. it either succeedes or fails, and does not interfere with other users doing the same (this, or their requests may fail e.g. due to a deleted feature that is referenced in a request that is serialized after).",
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"description": "Data to be uploaded.\n\nIf Content-Type is application/json, the data is expected directly in the request body.\n\nIf Content-Type is multipart/form-data, a zip-file is expcected containing both the data, and the other binary files (photos) associated with the data.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Update"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"multipart/form-data": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Update data stored in the string, interpreted in the same way as the request body would be, if the Content-Type was application/json."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"format": "binary",
|
||||||
|
"description": "A file containing the update data which will be interpreted in the same way as the request body would be, if the Content-Type was application/json."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "binary",
|
||||||
|
"description": "A photo that is to be added to a feature (new or existing). Is referenced from the 'data' via 'created_photos' and 'add_photos'."
|
||||||
|
},
|
||||||
|
"required": ["data"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "Update has been performed successfully."
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "There has been some problem with the request. Possible reasons are:\n\n * unsupported Content-Type of the request (i.e. other than application/json or multipart/form-data),\n * malformed JSON data, either directly in request body (when Content-Type is application/json), or in the 'data' field (when Content-Type is multipart/form-data),\n * malformed multipart/form-data request body,\n * IDs of created features are not unique,\n * 'created_photos' and/or 'add_photos' have been specified but the Content-Type is application/json,\n * the 'data' field is missing in the request body (when Content-Type is multipart/form-data),\n * the 'data' field contains more than 1 item (when Content-Type is multipart/form-data),\n * other fields (that are supposed to contain 1 photo each) contain more than 1 item (when Content-Type is multipart/form-data),\n * unsupported Content-Type of a photo (when request Content-Type is multipart/form-data).\n\nThe response body contains the error description in plain text.",
|
||||||
|
"content": {
|
||||||
|
"text/plain": {
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"malformed request body (application/json)": {
|
||||||
|
"value": "malfomred data: <description of error>"
|
||||||
|
},
|
||||||
|
"malformed request body (multipart/form-data)": {
|
||||||
|
"value": "malfomred multipart/form-data content"
|
||||||
|
},
|
||||||
|
"photos specified (application/json)": {
|
||||||
|
"value": "created_photos and/or add_photos present, but Content-Type is application/json"
|
||||||
|
},
|
||||||
|
"no 'data' field (multipart/form-data)": {
|
||||||
|
"value": "value 'data' is missing from the content"
|
||||||
|
},
|
||||||
|
"multiple items for 'data' field (multipart/form-data)": {
|
||||||
|
"value": "value 'data' does not contain exactly 1 item"
|
||||||
|
},
|
||||||
|
"malformed 'data' (multipart/form-data)": {
|
||||||
|
"value": "malformed 'data' value: <description of error>"
|
||||||
|
},
|
||||||
|
"non-unique created feature IDs (both)": {
|
||||||
|
"value": "created features do not have unique IDs"
|
||||||
|
},
|
||||||
|
"multiple items for another field than 'data' (multipart/form-data)": {
|
||||||
|
"value": "file item <name of field> does not contain exactly 1 file"
|
||||||
|
},
|
||||||
|
"unsupported photo Content-Type (multipart/form-data)": {
|
||||||
|
"value": "photo <name of field> has an unsupported Content-Type"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/data/people": {
|
||||||
|
"parameters": [{"$ref": "#/components/parameters/UserID"}],
|
||||||
|
"get": {
|
||||||
|
"operationId": "getPeople",
|
||||||
|
"tags": ["app"],
|
||||||
|
"summary": "Lists the users present in the system.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "List of users present in the system.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/User"
|
||||||
|
},
|
||||||
|
"description": "List of users."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/data/features": {
|
||||||
|
"parameters": [{"$ref": "#/components/parameters/UserID"}],
|
||||||
|
"get": {
|
||||||
|
"operationId": "getFeatures",
|
||||||
|
"tags": ["app"],
|
||||||
|
"summary": "Lists the features present in the system.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "List of features present in the system.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Feature"
|
||||||
|
},
|
||||||
|
"description": "List of features."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/data/features/{featureID}/photos/{photoID}": {
|
||||||
|
"parameters": [
|
||||||
|
{"$ref": "#/components/parameters/UserID"},
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "featureID",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"description": "ID of a feature."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "photoID",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"description": "ID of a photo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"get": {
|
||||||
|
"operationId": "getPhoto",
|
||||||
|
"tags": ["app"],
|
||||||
|
"summary": "Retrieves the specified photo of the specified feature.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "The requested photo. The Content-Type is the same as of the photo file stored on the server."
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Either the feature ID or the photo ID path parameter was malformed.",
|
||||||
|
"content": {
|
||||||
|
"text/plain": {
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"malformed feature ID": {
|
||||||
|
"value": "malformed feature ID"
|
||||||
|
},
|
||||||
|
"malfomred photo ID": {
|
||||||
|
"value": "malfomred photo ID"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Photo does not exist (for the given feature)."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/data/proposals": {
|
||||||
|
"parameters": [{"$ref": "#/components/parameters/UserID"}],
|
||||||
|
"get": {
|
||||||
|
"operationId": "getProposals",
|
||||||
|
"tags": ["app"],
|
||||||
|
"summary": "Lists the proposals submitted to the system.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "List of proposals submitted to the system.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/Proposal"
|
||||||
|
},
|
||||||
|
"description": "List of proposals."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/mappack": {
|
||||||
|
"parameters": [{"$ref": "#/components/parameters/UserID"}],
|
||||||
|
"get": {
|
||||||
|
"operationId": "getTilePack",
|
||||||
|
"tags": ["app"],
|
||||||
|
"summary": "Returns a file containing a pack of map tiles.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Tile pack file."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/build-info": {
|
||||||
|
"parameters": [{"$ref": "#/components/parameters/UserID"}],
|
||||||
|
"get": {
|
||||||
|
"operationId": "getBuildInfo",
|
||||||
|
"tags": ["debug", "utils"],
|
||||||
|
"summary": "Returns the info about the server build.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Server build info.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/BuildInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/hard-fail": {
|
||||||
|
"parameters": [{"$ref": "#/components/parameters/UserID"}],
|
||||||
|
"get": {
|
||||||
|
"operationId": "hardFail",
|
||||||
|
"tags": ["debug"],
|
||||||
|
"summary": "Debug endpoint for safe simulation of server-side error.",
|
||||||
|
"responses": {
|
||||||
|
"501": {
|
||||||
|
"description": "An error."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/soft-fail": {
|
||||||
|
"parameters": [{"$ref": "#/components/parameters/UserID"}],
|
||||||
|
"get": {
|
||||||
|
"operationId": "softFail",
|
||||||
|
"tags": ["debug"],
|
||||||
|
"summary": "Debug endpoint for safe simulation of an error reported through OK and json response body.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "An error.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"error": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/app-versions": {
|
||||||
|
"parameters": [{"$ref": "#/components/parameters/UserID"}],
|
||||||
|
"get": {
|
||||||
|
"operationId": "getAppVersions",
|
||||||
|
"tags": ["utils", "debug"],
|
||||||
|
"summary": "Retrieves the known/registered app versions.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "List of known/registered app versions.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/AppVersionInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"operationId": "postAppVersion",
|
||||||
|
"tags": ["utils"],
|
||||||
|
"summary": "Registers an app version.",
|
||||||
|
"requestBody": {
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/AppVersionInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "App version info."
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "Version has been registered."
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Malformed version info."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/app-versions/{version}": {
|
||||||
|
"parameters": [
|
||||||
|
{"$ref": "#/components/parameters/UserID"},
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "version",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"get": {
|
||||||
|
"operationId": "getAppVersion",
|
||||||
|
"tags": ["app"],
|
||||||
|
"summary": "Retrieves an app version info.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "App version info.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/AppVersionInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Version not specified."
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Requested version not found."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"operationId": "deleteAppVersion",
|
||||||
|
"tags": ["utils"],
|
||||||
|
"summary": "Deletes an app version.",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "The specified version has been deleted."
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Version not specified."
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "The specified version not found."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/reinit": {
|
||||||
|
"parameters": [{"$ref": "#/components/parameters/UserID"}],
|
||||||
|
"post": {
|
||||||
|
"operationId": "reinitDb",
|
||||||
|
"tags": ["debug", "utils"],
|
||||||
|
"summary": "Reinitializes DB (deletes all data).",
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": "DB has been reinitialized."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/usage-info": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "getUsageInfo",
|
||||||
|
"tags": ["utils", "debug"],
|
||||||
|
"summary": "Similar to /data/people, but used app version and times of last contact, upload, and download are retreived as well.",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "User usage info.",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/UserInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,34 +1,53 @@
|
|||||||
module cernobor.cz/oko-server
|
module cernobor.cz/oko-server
|
||||||
|
|
||||||
go 1.19
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
crawshaw.io/sqlite v0.3.2
|
github.com/consbio/mbtileserver v0.9.0
|
||||||
github.com/consbio/mbtileserver v0.8.2
|
github.com/gin-gonic/gin v1.9.1
|
||||||
github.com/gin-gonic/gin v1.7.7
|
|
||||||
github.com/paulmach/go.geojson v1.4.0
|
github.com/paulmach/go.geojson v1.4.0
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.9.3
|
||||||
|
zombiezen.com/go/sqlite v0.13.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/brendan-ward/mbtiles-go v0.1.1-0.20220129145719-67a7dabdbaab // indirect
|
crawshaw.io/sqlite v0.3.3-0.20211227050848-2cdb5c1a86a1 // indirect
|
||||||
github.com/coreos/go-semver v0.3.0
|
github.com/bytedance/sonic v1.9.1 // indirect
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
|
golang.org/x/net v0.10.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
modernc.org/libc v1.24.1 // indirect
|
||||||
|
modernc.org/mathutil v1.5.0 // indirect
|
||||||
|
modernc.org/memory v1.6.0 // indirect
|
||||||
|
modernc.org/sqlite v1.23.0 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/brendan-ward/mbtiles-go v0.1.1-0.20220830154734-a6cb9b848bab // indirect
|
||||||
|
github.com/coreos/go-semver v0.3.1
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-playground/locales v0.14.0 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.10.0 // indirect
|
github.com/go-playground/validator/v10 v10.14.1 // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/leodido/go-urn v1.2.1 // indirect
|
github.com/leodido/go-urn v1.2.4 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/mssola/user_agent v0.5.3
|
github.com/mssola/user_agent v0.6.0
|
||||||
github.com/ugorji/go/codec v1.2.6 // indirect
|
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce // indirect
|
golang.org/x/crypto v0.9.0 // indirect
|
||||||
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539
|
golang.org/x/image v0.7.0
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
|
golang.org/x/sys v0.8.0 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.9.0 // indirect
|
||||||
google.golang.org/protobuf v1.27.1 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,851 +1,149 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
|
||||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
|
||||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
|
||||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
|
||||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
|
||||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
|
||||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
|
||||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
|
||||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
|
||||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
|
||||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
|
||||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
|
||||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
|
||||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
|
||||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
|
||||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
|
||||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
|
||||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
|
||||||
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
|
|
||||||
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
|
|
||||||
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
|
|
||||||
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
|
|
||||||
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
|
|
||||||
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
|
|
||||||
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
|
||||||
cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM=
|
|
||||||
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
|
||||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
|
||||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
|
||||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
|
||||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
|
||||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
|
||||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
|
||||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
|
||||||
cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
|
|
||||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
|
||||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
|
||||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
|
||||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
|
||||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
|
||||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
|
||||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
|
||||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
|
||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
|
||||||
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797 h1:yDf7ARQc637HoxDho7xjqdvO5ZA2Yb+xzv/fOnnvZzw=
|
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797 h1:yDf7ARQc637HoxDho7xjqdvO5ZA2Yb+xzv/fOnnvZzw=
|
||||||
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk=
|
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk=
|
||||||
crawshaw.io/sqlite v0.3.2 h1:N6IzTjkiw9FItHAa0jp+ZKC6tuLzXqAYIv+ccIWos1I=
|
crawshaw.io/sqlite v0.3.3-0.20211227050848-2cdb5c1a86a1 h1:Ee5qKxzDpjFjX2tdxl8NlPCTr3PDpagnyf0jL5ow+PY=
|
||||||
crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
|
crawshaw.io/sqlite v0.3.3-0.20211227050848-2cdb5c1a86a1/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
github.com/brendan-ward/mbtiles-go v0.1.1-0.20220830154734-a6cb9b848bab h1:/+iZRJ5VeHYqgQQtfiAaP6niUH+2zSfox6QetbqB6eI=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/brendan-ward/mbtiles-go v0.1.1-0.20220830154734-a6cb9b848bab/go.mod h1:PjU6MOcQtVNQbHT42VnBVLQh4pze1Hy+6AkwRoW4BBY=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/consbio/mbtileserver v0.9.0 h1:HV7mNSeOcr25ew8qkKVyt0jcw3859zTVnIhPbcv6Kao=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/consbio/mbtileserver v0.9.0/go.mod h1:S0NvNKLJEeUOdVa8vklmpyiiB4Jsxh6wVjaGSmlXamg=
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||||
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
|
||||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
|
||||||
github.com/brendan-ward/mbtiles-go v0.1.1-0.20220129145719-67a7dabdbaab h1:KC2TqbUmfkIrTwVpkH1ysJiZicPoSyb6chH3JxKHqBM=
|
|
||||||
github.com/brendan-ward/mbtiles-go v0.1.1-0.20220129145719-67a7dabdbaab/go.mod h1:rlKkU0/sjOysMB+dvVI+b90UyzmD5alQK7KlhJplVrg=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
|
||||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
|
||||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/consbio/mbtileserver v0.8.2 h1:iXOBkCp4r/7Z7wC4sw6dYkFAJnuyVpQMu0dbT+RHSxE=
|
|
||||||
github.com/consbio/mbtileserver v0.8.2/go.mod h1:lVBCXeAL6OzooRXWbQ/MZFGFtwm/0A1fkeNTf9T4gzA=
|
|
||||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
|
|
||||||
github.com/evalphobia/logrus_sentry v0.8.2/go.mod h1:pKcp+vriitUqu9KiWj/VRFbRfFNUwz95/UkgG8a6MNc=
|
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
|
||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
|
||||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
|
||||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
|
||||||
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||||
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
|
||||||
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
|
|
||||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
|
||||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
|
||||||
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
|
|
||||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
|
||||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
|
||||||
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/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
|
||||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
|
||||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
|
||||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
|
||||||
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
|
||||||
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
|
||||||
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
|
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
|
||||||
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
|
||||||
github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
|
||||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
|
||||||
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
|
||||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
|
||||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
|
||||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
|
||||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
|
||||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
|
||||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
|
||||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
|
||||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
|
||||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
|
||||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
|
||||||
github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
|
|
||||||
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
|
||||||
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
|
||||||
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
|
||||||
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
|
||||||
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
|
|
||||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
|
||||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|
||||||
github.com/labstack/echo/v4 v4.6.1/go.mod h1:RnjgMWNDB9g/HucVWhQYNQP9PvbYf6adqftqryo7s9k=
|
|
||||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
|
||||||
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
|
||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
|
||||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
|
||||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
|
||||||
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
|
|
||||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
|
||||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
|
||||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
|
||||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
|
||||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
|
||||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
|
||||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
|
||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
|
||||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
|
||||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
|
||||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
|
||||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
|
||||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
github.com/mssola/user_agent v0.5.3 h1:lBRPML9mdFuIZgI2cmlQ+atbpJdLdeVl2IDodjBR578=
|
github.com/mssola/user_agent v0.6.0 h1:uwPR4rtWlCHRFyyP9u2KOV0u8iQXmS7Z7feTrstQwk4=
|
||||||
github.com/mssola/user_agent v0.5.3/go.mod h1:TTPno8LPY3wAIEKRpAtkdMT0f8SE24pLRGPahjCH4uw=
|
github.com/mssola/user_agent v0.6.0/go.mod h1:TTPno8LPY3wAIEKRpAtkdMT0f8SE24pLRGPahjCH4uw=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
|
||||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
|
||||||
github.com/paulmach/go.geojson v1.4.0 h1:5x5moCkCtDo5x8af62P9IOAYGQcYHtxz2QJ3x1DoCgY=
|
github.com/paulmach/go.geojson v1.4.0 h1:5x5moCkCtDo5x8af62P9IOAYGQcYHtxz2QJ3x1DoCgY=
|
||||||
github.com/paulmach/go.geojson v1.4.0/go.mod h1:YaKx1hKpWF+T2oj2lFJPsW/t1Q5e1jQI61eoQSTwpIs=
|
github.com/paulmach/go.geojson v1.4.0/go.mod h1:YaKx1hKpWF+T2oj2lFJPsW/t1Q5e1jQI61eoQSTwpIs=
|
||||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
|
||||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
|
||||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
|
||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
|
||||||
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
|
||||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
|
||||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
|
||||||
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
|
||||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
|
||||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
|
||||||
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
|
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
|
||||||
github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||||
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
|
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
|
||||||
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
|
||||||
go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
|
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|
||||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|
||||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
|
||||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
|
||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
|
||||||
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
|
||||||
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce h1:Roh6XWxHFKrPgC/EQhVubSAGQ6Ozk6IdxHSzt1mR0EI=
|
|
||||||
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
|
||||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
|
||||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
|
||||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 h1:/eM0PCrQI2xd471rI+snWuu251/+/jpBpZqir2mPdnU=
|
|
||||||
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
|
||||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||||
golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211214170744-3b038e5940ed/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
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/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
|
||||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
|
||||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
|
||||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
|
||||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
|
||||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
|
||||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
|
||||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
|
||||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
|
||||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
|
||||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
|
||||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
|
||||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
|
||||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
|
||||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
|
||||||
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
|
|
||||||
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
|
|
||||||
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
|
||||||
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
|
||||||
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
|
|
||||||
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
|
||||||
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
|
||||||
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
|
|
||||||
google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
|
|
||||||
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
|
|
||||||
google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
|
||||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
|
||||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
|
||||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
|
||||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
|
||||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
|
||||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
|
||||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
|
||||||
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
|
||||||
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
|
||||||
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
|
||||||
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
|
||||||
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
|
||||||
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
|
||||||
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
|
||||||
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
|
||||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
|
||||||
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
|
||||||
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
|
||||||
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
|
||||||
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
|
||||||
google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
|
||||||
google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
|
||||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
|
||||||
google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
|
||||||
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
|
||||||
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
|
||||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
|
||||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
|
||||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
|
||||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
|
||||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
|
||||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
|
||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
|
||||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
|
||||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
|
||||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
|
||||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
|
||||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
|
||||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
|
||||||
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
|
||||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
|
||||||
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
|
||||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
|
||||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
modernc.org/sqlite v1.23.0 h1:MWTFBI5H1WLnXpNBh/BTruBVqzzoh28DA0iOnlkkRaM=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
modernc.org/sqlite v1.23.0/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
zombiezen.com/go/sqlite v0.13.0 h1:iEeyVqcm3fk5PCA8OQBhBxPnqrP4yYuVJBF+XZpSnOE=
|
||||||
|
zombiezen.com/go/sqlite v0.13.0/go.mod h1:Ht/5Rg3Ae2hoyh1I7gbWtWAl89CNocfqeb/aAMTkJr4=
|
||||||
|
|||||||
@@ -23,14 +23,13 @@ func main() {
|
|||||||
tilepackFileArg := flag.String("tilepack", "", "File that will be sent to clients when they request a tile pack, also used to serve tiles in online mode. Required.")
|
tilepackFileArg := flag.String("tilepack", "", "File that will be sent to clients when they request a tile pack, also used to serve tiles in online mode. Required.")
|
||||||
portArg := flag.Int("port", 8080, "Port where the server will listen to. Default is 8080.")
|
portArg := flag.Int("port", 8080, "Port where the server will listen to. Default is 8080.")
|
||||||
dbFileArg := flag.String("dbfile", "./data.sqlite3", "File that holds the server's sqlite3 database. Will be created if it does not exist. Default is \"./data.sqlite3\".")
|
dbFileArg := flag.String("dbfile", "./data.sqlite3", "File that holds the server's sqlite3 database. Will be created if it does not exist. Default is \"./data.sqlite3\".")
|
||||||
apkFileArg := flag.String("apk", "", "APK file with the client app. If not specified, no APK will be available (404).")
|
|
||||||
reinitDBArg := flag.Bool("reinit-db", false, "Reinitializes the DB, which means all the tables will be recreated, deleting all data.")
|
|
||||||
minZoomArg := flag.Int("min-zoom", 1, "Minimum zoom that will be sent to clients.")
|
minZoomArg := flag.Int("min-zoom", 1, "Minimum zoom that will be sent to clients.")
|
||||||
defaultCenterLatArg := flag.Float64("default-center-lat", 0, "Latitude of the default map center.")
|
defaultCenterLatArg := flag.Float64("default-center-lat", 0, "Latitude of the default map center.")
|
||||||
defaultCenterLngArg := flag.Float64("default-center-lng", 0, "Longitude of the default map center.")
|
defaultCenterLngArg := flag.Float64("default-center-lng", 0, "Longitude of the default map center.")
|
||||||
maxPhotoXArg := flag.Int("max-photo-width", 0, "Maximum width of photos. 0 means no limit.")
|
maxPhotoXArg := flag.Int("max-photo-width", 0, "Maximum width of photos. 0 means no limit.")
|
||||||
maxPhotoYArg := flag.Int("max-photo-height", 0, "Maximum height of photos. 0 means no limit.")
|
maxPhotoYArg := flag.Int("max-photo-height", 0, "Maximum height of photos. 0 means no limit.")
|
||||||
photoQualityArg := flag.Int("photo-quality", 90, "Photo JPEG quality.")
|
photoQualityArg := flag.Int("photo-quality", 90, "Photo JPEG quality.")
|
||||||
|
debug := flag.Bool("debug", false, "If specified, logging level will be set to debug instead of info.")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@@ -56,8 +55,6 @@ func main() {
|
|||||||
Port: *portArg,
|
Port: *portArg,
|
||||||
DbPath: *dbFileArg,
|
DbPath: *dbFileArg,
|
||||||
TilepackPath: *tilepackFileArg,
|
TilepackPath: *tilepackFileArg,
|
||||||
ApkPath: *apkFileArg,
|
|
||||||
ReinitDB: *reinitDBArg,
|
|
||||||
MinZoom: *minZoomArg,
|
MinZoom: *minZoomArg,
|
||||||
DefaultCenter: models.Coords{
|
DefaultCenter: models.Coords{
|
||||||
Lat: *defaultCenterLatArg,
|
Lat: *defaultCenterLatArg,
|
||||||
@@ -66,6 +63,7 @@ func main() {
|
|||||||
MaxPhotoX: *maxPhotoXArg,
|
MaxPhotoX: *maxPhotoXArg,
|
||||||
MaxPhotoY: *maxPhotoYArg,
|
MaxPhotoY: *maxPhotoYArg,
|
||||||
PhotoQuality: *photoQualityArg,
|
PhotoQuality: *photoQualityArg,
|
||||||
|
Debug: *debug,
|
||||||
})
|
})
|
||||||
|
|
||||||
sigs := make(chan os.Signal, 1)
|
sigs := make(chan os.Signal, 1)
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ type User struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserInfo struct {
|
||||||
|
User
|
||||||
|
AppVersion *semver.Version `json:"app_version"`
|
||||||
|
LastSeenTime *time.Time `json:"last_seen_time"`
|
||||||
|
LastUploadTime *time.Time `json:"last_upload_time"`
|
||||||
|
LastDownloadTime *time.Time `json:"last_download_time"`
|
||||||
|
}
|
||||||
|
|
||||||
type Feature struct {
|
type Feature struct {
|
||||||
// ID is an ID of the feature.
|
// ID is an ID of the feature.
|
||||||
// When the feature is submitted by a client for creation (i.e. in Update.Create) it is considered a 'local' ID which must be unique across all submitted features.
|
// When the feature is submitted by a client for creation (i.e. in Update.Create) it is considered a 'local' ID which must be unique across all submitted features.
|
||||||
@@ -83,6 +91,7 @@ type HandshakeResponse struct {
|
|||||||
type Data struct {
|
type Data struct {
|
||||||
Users []User `json:"users"`
|
Users []User `json:"users"`
|
||||||
Features []Feature `json:"features"`
|
Features []Feature `json:"features"`
|
||||||
|
Proposals []Proposal `json:"proposals"`
|
||||||
PhotoMetadata map[string]PhotoMetadata `json:"photo_metadata,omitempty"`
|
PhotoMetadata map[string]PhotoMetadata `json:"photo_metadata,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -6,7 +6,9 @@ const (
|
|||||||
URIHardFail = "/hard-fail"
|
URIHardFail = "/hard-fail"
|
||||||
URISoftFail = "/soft-fail"
|
URISoftFail = "/soft-fail"
|
||||||
URIAppVersions = "/app-versions"
|
URIAppVersions = "/app-versions"
|
||||||
|
URIAppVersion = "/app-versions/:version"
|
||||||
URIReinit = "/reinit"
|
URIReinit = "/reinit"
|
||||||
|
URIUsageInfo = "/usage-info"
|
||||||
URIMapPack = "/mappack"
|
URIMapPack = "/mappack"
|
||||||
URIHandshake = "/handshake"
|
URIHandshake = "/handshake"
|
||||||
URIData = "/data"
|
URIData = "/data"
|
||||||
@@ -18,5 +20,6 @@ const (
|
|||||||
URITileserver = URITileserverRoot + "/*x"
|
URITileserver = URITileserverRoot + "/*x"
|
||||||
URITileTemplate = URITileserverRoot + "/map/tiles/{z}/{x}/{y}.pbf"
|
URITileTemplate = URITileserverRoot + "/map/tiles/{z}/{x}/{y}.pbf"
|
||||||
|
|
||||||
AppName = "OKO"
|
AppName = "OKO"
|
||||||
|
UserIDHeader = "X-User-ID"
|
||||||
)
|
)
|
||||||
|
|||||||
+229
@@ -0,0 +1,229 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"zombiezen.com/go/sqlite"
|
||||||
|
"zombiezen.com/go/sqlite/sqlitemigration"
|
||||||
|
"zombiezen.com/go/sqlite/sqlitex"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) cleanupDb() {
|
||||||
|
close(s.checkpointNotice)
|
||||||
|
s.log.Info("Closing db connection pool...")
|
||||||
|
s.dbpool.Close()
|
||||||
|
|
||||||
|
// manually force truncate checkpoint
|
||||||
|
conn, err := sqlite.OpenConn(fmt.Sprintf("file:%s", s.config.DbPath), 0)
|
||||||
|
if err != nil {
|
||||||
|
s.log.WithError(err).Error("Failed to open connection for final checkpoint.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = sqlitex.Execute(conn, "vacuum", nil)
|
||||||
|
if err != nil {
|
||||||
|
s.log.WithError(err).Error("Failed to vacuum db.")
|
||||||
|
}
|
||||||
|
s.checkpointDb(conn, true)
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) getDbConn() *sqlite.Conn {
|
||||||
|
conn, err := s.dbpool.Get(s.ctx)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) returnDbConn(conn *sqlite.Conn) {
|
||||||
|
s.dbpool.Put(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withDbConn[T any](s *Server, f func(conn *sqlite.Conn) T) T {
|
||||||
|
conn := s.getDbConn()
|
||||||
|
defer s.returnDbConn(conn)
|
||||||
|
return f(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) checkpointDb(conn *sqlite.Conn, truncate bool) {
|
||||||
|
var query string
|
||||||
|
if truncate {
|
||||||
|
query = "PRAGMA wal_checkpoint(TRUNCATE)"
|
||||||
|
} else {
|
||||||
|
query = "PRAGMA wal_checkpoint(RESTART)"
|
||||||
|
}
|
||||||
|
stmt, _, err := conn.PrepareTransient(query)
|
||||||
|
if err != nil {
|
||||||
|
s.log.WithError(err).Error("Failed to prepare checkpoint query.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer stmt.Finalize()
|
||||||
|
|
||||||
|
has, err := stmt.Step()
|
||||||
|
if err != nil {
|
||||||
|
s.log.WithError(err).Error("Failed to step through checkpoint query.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !has {
|
||||||
|
s.log.Error("Checkpoint query returned no rows.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
blocked := stmt.ColumnInt(0)
|
||||||
|
noWalPages := stmt.ColumnInt(1)
|
||||||
|
noReclaimedPages := stmt.ColumnInt(2)
|
||||||
|
if blocked == 1 {
|
||||||
|
s.log.Warn("Checkpoint query was blocked.")
|
||||||
|
}
|
||||||
|
s.log.Debugf("Checkpoint complete. %d pages written to WAL, %d pages written back to DB.", noWalPages, noReclaimedPages)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) setupDB() error {
|
||||||
|
s.dbAvailable.Store(false)
|
||||||
|
s.log.Debugf("Using db %s", s.config.DbPath)
|
||||||
|
|
||||||
|
ready := make(chan struct{})
|
||||||
|
migErr := make(chan error)
|
||||||
|
s.dbpool = sqlitemigration.NewPool(fmt.Sprintf("file:%s", s.config.DbPath), sqlSchema, sqlitemigration.Options{
|
||||||
|
PoolSize: 10,
|
||||||
|
PrepareConn: func(conn *sqlite.Conn) error {
|
||||||
|
return sqlitex.ExecuteTransient(conn, "PRAGMA foreign_keys = ON;", nil)
|
||||||
|
},
|
||||||
|
OnReady: func() {
|
||||||
|
close(ready)
|
||||||
|
},
|
||||||
|
OnError: func(err error) {
|
||||||
|
migErr <- err
|
||||||
|
},
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case <-ready:
|
||||||
|
case err := <-migErr:
|
||||||
|
return fmt.Errorf("error during db migration: %w", err)
|
||||||
|
}
|
||||||
|
s.checkpointNotice = make(chan struct{})
|
||||||
|
|
||||||
|
// aggressively checkpoint the database on idle times
|
||||||
|
go func() {
|
||||||
|
s.log.Debug("Starting manual restart checkpointing.")
|
||||||
|
defer s.log.Debug("Manual restart checkpointing stopped.")
|
||||||
|
delay := time.Minute * 15
|
||||||
|
var (
|
||||||
|
timer <-chan time.Time
|
||||||
|
ok bool
|
||||||
|
)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case _, ok = <-s.checkpointNotice:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
timer = time.After(delay)
|
||||||
|
case <-timer:
|
||||||
|
withDbConn(s, func(conn *sqlite.Conn) any {
|
||||||
|
s.checkpointDb(conn, false)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
timer = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
s.dbAvailable.Store(true)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) requestCheckpoint() {
|
||||||
|
go func() {
|
||||||
|
s.checkpointNotice <- struct{}{}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) reinitDb() error {
|
||||||
|
s.log.Debug("Reinitializing db.")
|
||||||
|
s.dbAvailable.Store(false)
|
||||||
|
defer s.dbAvailable.Store(true)
|
||||||
|
close(s.checkpointNotice)
|
||||||
|
err := s.dbpool.Close()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to close db: %w", err)
|
||||||
|
}
|
||||||
|
s.log.Debug("Removing main db file.")
|
||||||
|
err = os.Remove(s.config.DbPath)
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("failed to remove db file %s: %w", s.config.DbPath, err)
|
||||||
|
}
|
||||||
|
s.log.Debug("Removing WAL file.")
|
||||||
|
err = os.Remove(s.config.DbPath + "-wal")
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("failed to remove db-wal file %s-wal: %w", s.config.DbPath, err)
|
||||||
|
}
|
||||||
|
s.log.Debug("Initializing db.")
|
||||||
|
err = s.setupDB()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to setup db during reinit")
|
||||||
|
}
|
||||||
|
s.log.Debug("DB reinitialized.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SQL schema
|
||||||
|
|
||||||
|
//go:embed sql_schema/V*.sql
|
||||||
|
var sqlSchemaFiles embed.FS
|
||||||
|
var sqlSchema sqlitemigration.Schema = func() sqlitemigration.Schema {
|
||||||
|
type migration struct {
|
||||||
|
content string
|
||||||
|
version int
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
entries, err := sqlSchemaFiles.ReadDir("sql_schema")
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("failed to read sql_schema migrations: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
pattern := regexp.MustCompile("^V([0-9]+)_(.*)[.][sS][qQ][lL]$")
|
||||||
|
migrations := []*migration{}
|
||||||
|
for _, entry := range entries {
|
||||||
|
name := entry.Name()
|
||||||
|
if entry.IsDir() {
|
||||||
|
panic(fmt.Errorf("embedded sql migration '%s' is a directory", name))
|
||||||
|
}
|
||||||
|
matches := pattern.FindStringSubmatch(name)
|
||||||
|
if matches == nil {
|
||||||
|
panic(fmt.Errorf("embedded sql migration '%s' does not match the filename pattern", name))
|
||||||
|
}
|
||||||
|
if len(matches) != 3 {
|
||||||
|
panic(fmt.Errorf("embedded sql migration '%s' does not have the correct number of submatches", name))
|
||||||
|
}
|
||||||
|
version, err := strconv.Atoi(matches[1])
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("failed to parse version number of migration '%s': %w", name, err))
|
||||||
|
}
|
||||||
|
migName := matches[2]
|
||||||
|
file := path.Join("sql_schema", name)
|
||||||
|
content, err := sqlSchemaFiles.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("failed to read embedded migration %s", entry.Name()))
|
||||||
|
}
|
||||||
|
migrations = append(migrations, &migration{
|
||||||
|
content: string(content),
|
||||||
|
version: version,
|
||||||
|
name: migName,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
sort.Slice(migrations, func(i, j int) bool {
|
||||||
|
return migrations[i].version < migrations[j].version
|
||||||
|
})
|
||||||
|
|
||||||
|
return sqlitemigration.Schema{
|
||||||
|
Migrations: Map(func(m *migration) string { return m.content }, migrations),
|
||||||
|
}
|
||||||
|
}()
|
||||||
+192
-52
@@ -17,6 +17,8 @@ import (
|
|||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/mssola/user_agent"
|
"github.com/mssola/user_agent"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"zombiezen.com/go/sqlite"
|
||||||
|
"zombiezen.com/go/sqlite/sqlitex"
|
||||||
)
|
)
|
||||||
|
|
||||||
func internalError(gc *gin.Context, err error) {
|
func internalError(gc *gin.Context, err error) {
|
||||||
@@ -35,55 +37,108 @@ func (s *Server) setupRouter() *gin.Engine {
|
|||||||
router.Use(gin.Recovery())
|
router.Use(gin.Recovery())
|
||||||
|
|
||||||
// logging
|
// logging
|
||||||
ginLogger := logrus.New()
|
|
||||||
hostname, err := os.Hostname()
|
hostname, err := os.Hostname()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
hostname = "unknown"
|
hostname = "unknown"
|
||||||
}
|
}
|
||||||
router.Use(func(gc *gin.Context) {
|
router.Use(
|
||||||
path := gc.Request.URL.Path
|
func(gc *gin.Context) {
|
||||||
start := time.Now()
|
path := gc.Request.URL.Path
|
||||||
gc.Next()
|
start := time.Now()
|
||||||
stop := time.Since(start)
|
gc.Next()
|
||||||
latency := int(math.Ceil(float64(stop.Nanoseconds()) / 1_000_000.0))
|
stop := time.Since(start)
|
||||||
statusCode := gc.Writer.Status()
|
latency := int(math.Ceil(float64(stop.Nanoseconds()) / 1_000_000.0))
|
||||||
clientIP := gc.ClientIP()
|
statusCode := gc.Writer.Status()
|
||||||
clientUserAgent := gc.Request.UserAgent()
|
clientIP := gc.ClientIP()
|
||||||
referer := gc.Request.Referer()
|
clientUserAgent := gc.Request.UserAgent()
|
||||||
dataLength := gc.Writer.Size()
|
userId := gc.GetHeader(UserIDHeader)
|
||||||
if dataLength < 0 {
|
referer := gc.Request.Referer()
|
||||||
dataLength = 0
|
dataLength := gc.Writer.Size()
|
||||||
}
|
if dataLength < 0 {
|
||||||
entry := ginLogger.WithFields(logrus.Fields{
|
dataLength = 0
|
||||||
"hostname": hostname,
|
|
||||||
"statusCode": statusCode,
|
|
||||||
"latency": latency,
|
|
||||||
"clientIP": clientIP,
|
|
||||||
"method": gc.Request.Method,
|
|
||||||
"path": path,
|
|
||||||
"referer": referer,
|
|
||||||
"dataLength": dataLength,
|
|
||||||
"userAgent": clientUserAgent,
|
|
||||||
})
|
|
||||||
|
|
||||||
if len(gc.Errors) > 0 {
|
|
||||||
entry.Error(gc.Errors.ByType(gin.ErrorTypePrivate).String())
|
|
||||||
} else {
|
|
||||||
msg := fmt.Sprintf(
|
|
||||||
"%s - %s [%s] \"%s %s\" %d %d \"%s\" \"%s\" (%dms)",
|
|
||||||
clientIP, hostname, time.Now().Format(time.RFC3339), gc.Request.Method, path, statusCode, dataLength, referer, clientUserAgent, latency,
|
|
||||||
)
|
|
||||||
if statusCode >= 500 {
|
|
||||||
entry.Error(msg)
|
|
||||||
} else if statusCode >= 400 {
|
|
||||||
entry.Warn(msg)
|
|
||||||
} else if path == URIPing {
|
|
||||||
entry.Debug(msg)
|
|
||||||
} else {
|
|
||||||
entry.Info(msg)
|
|
||||||
}
|
}
|
||||||
}
|
entry := s.log.WithFields(logrus.Fields{
|
||||||
})
|
"hostname": hostname,
|
||||||
|
"statusCode": statusCode,
|
||||||
|
"latency": latency,
|
||||||
|
"clientIP": clientIP,
|
||||||
|
"method": gc.Request.Method,
|
||||||
|
"path": path,
|
||||||
|
"referer": referer,
|
||||||
|
"dataLength": dataLength,
|
||||||
|
"userAgent": clientUserAgent,
|
||||||
|
"userID": userId,
|
||||||
|
})
|
||||||
|
|
||||||
|
if len(gc.Errors) > 0 {
|
||||||
|
entry.Error(gc.Errors.ByType(gin.ErrorTypePrivate).String())
|
||||||
|
} else {
|
||||||
|
msg := fmt.Sprintf(
|
||||||
|
"%s - %s [%s] \"%s %s\" %d %d \"%s\" \"%s\" (%dms)",
|
||||||
|
clientIP, hostname, time.Now().Format(time.RFC3339), gc.Request.Method, path, statusCode, dataLength, referer, clientUserAgent, latency,
|
||||||
|
)
|
||||||
|
if statusCode >= 500 {
|
||||||
|
entry.Error(msg)
|
||||||
|
} else if statusCode >= 400 {
|
||||||
|
entry.Warn(msg)
|
||||||
|
} else if path == URIPing {
|
||||||
|
entry.Debug(msg)
|
||||||
|
} else {
|
||||||
|
entry.Info(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func(gc *gin.Context) {
|
||||||
|
if !s.dbAvailable.Load() {
|
||||||
|
gc.AbortWithError(http.StatusServiceUnavailable, fmt.Errorf("server database is not ready/available"))
|
||||||
|
gc.Header("Retry-After", "60")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gc.Next()
|
||||||
|
},
|
||||||
|
func(gc *gin.Context) {
|
||||||
|
userIdStr := gc.GetHeader(UserIDHeader)
|
||||||
|
userIdPresent := userIdStr != ""
|
||||||
|
var userId int64
|
||||||
|
var userIdErr error
|
||||||
|
if userIdPresent {
|
||||||
|
userId, userIdErr = strconv.ParseInt(userIdStr, 10, 0)
|
||||||
|
}
|
||||||
|
appVersion, appVersionErr := extractAppVersion(gc)
|
||||||
|
if userIdErr != nil {
|
||||||
|
gc.Error(fmt.Errorf("malformed %s: %w", UserIDHeader, userIdErr))
|
||||||
|
} else if userIdPresent {
|
||||||
|
gc.Set("uid", userId)
|
||||||
|
var err error
|
||||||
|
if appVersion == nil {
|
||||||
|
err = withDbConn(s, func(conn *sqlite.Conn) error {
|
||||||
|
err := sqlitex.Execute(conn, "update users set last_seen_time = ? where id = ?", &sqlitex.ExecOptions{
|
||||||
|
Args: []interface{}{time.Now().Unix(), userId},
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
err = withDbConn(s, func(conn *sqlite.Conn) error {
|
||||||
|
err := sqlitex.Execute(conn, "update users set app_version = ?, last_seen_time = ? where id = ?", &sqlitex.ExecOptions{
|
||||||
|
Args: []interface{}{appVersion, time.Now().Unix(), userId},
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
gc.AbortWithError(http.StatusInternalServerError, fmt.Errorf("failed to store user data into db: %w", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if appVersion != nil {
|
||||||
|
gc.Set("app-version", appVersion)
|
||||||
|
}
|
||||||
|
if appVersionErr != nil {
|
||||||
|
gc.Error(appVersionErr)
|
||||||
|
gc.Set("app-version-error", appVersionErr.Error())
|
||||||
|
}
|
||||||
|
gc.Next()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
// tileserver
|
// tileserver
|
||||||
router.GET(URITileserver, gin.WrapH(s.tileserverSvSet.Handler()))
|
router.GET(URITileserver, gin.WrapH(s.tileserverSvSet.Handler()))
|
||||||
@@ -116,7 +171,10 @@ func (s *Server) setupRouter() *gin.Engine {
|
|||||||
})
|
})
|
||||||
router.GET(URIAppVersions, s.handleGETAppVersions)
|
router.GET(URIAppVersions, s.handleGETAppVersions)
|
||||||
router.POST(URIAppVersions, s.handlePOSTAppVersions)
|
router.POST(URIAppVersions, s.handlePOSTAppVersions)
|
||||||
|
router.GET(URIAppVersion, s.handleGETAppVersion)
|
||||||
|
router.DELETE(URIAppVersion, s.handleDELETEAppVersion)
|
||||||
router.POST(URIReinit, s.handlePOSTReset)
|
router.POST(URIReinit, s.handlePOSTReset)
|
||||||
|
router.GET(URIUsageInfo, s.handleGETUsageInfo)
|
||||||
|
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
@@ -136,9 +194,19 @@ func extractAppVersion(gc *gin.Context) (*semver.Version, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleGETPing(gc *gin.Context) {
|
func (s *Server) handleGETPing(gc *gin.Context) {
|
||||||
version, err := extractAppVersion(gc)
|
versionRaw, exists := gc.Get("app-version")
|
||||||
if err != nil {
|
if !exists {
|
||||||
badRequest(gc, err)
|
versionErr := gc.GetString("app-version-error")
|
||||||
|
if versionErr != "" {
|
||||||
|
badRequest(gc, fmt.Errorf("malformed app version: %v", &versionErr))
|
||||||
|
} else {
|
||||||
|
badRequest(gc, fmt.Errorf("app version not specified"))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
version, ok := versionRaw.(*semver.Version)
|
||||||
|
if !ok {
|
||||||
|
internalError(gc, fmt.Errorf("malformed app version extracted"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,13 +248,51 @@ func (s *Server) handlePOSTAppVersions(gc *gin.Context) {
|
|||||||
gc.Status(http.StatusNoContent)
|
gc.Status(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handlePOSTReset(gc *gin.Context) {
|
func (s *Server) handleGETAppVersion(gc *gin.Context) {
|
||||||
err := s.initDB(true)
|
version := gc.Param("version")
|
||||||
|
if version == "" {
|
||||||
|
badRequest(gc, fmt.Errorf("version not provided"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ver, err := s.getAppVersion(version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
internalError(gc, err)
|
internalError(gc, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gc.Status(http.StatusOK)
|
if ver == nil {
|
||||||
|
gc.Status(http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gc.JSON(http.StatusOK, ver)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleDELETEAppVersion(gc *gin.Context) {
|
||||||
|
version := gc.Param("version")
|
||||||
|
if version == "" {
|
||||||
|
badRequest(gc, fmt.Errorf("version not provided"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
deleted, err := s.deleteAppVersion(version)
|
||||||
|
if err != nil {
|
||||||
|
internalError(gc, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !deleted {
|
||||||
|
gc.Status(http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gc.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) handlePOSTReset(gc *gin.Context) {
|
||||||
|
err := s.reinitDb()
|
||||||
|
if err != nil {
|
||||||
|
internalError(gc, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gc.Status(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleGETTilepack(gc *gin.Context) {
|
func (s *Server) handleGETTilepack(gc *gin.Context) {
|
||||||
@@ -229,6 +335,8 @@ func (s *Server) handlePOSTHandshake(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleGETData(gc *gin.Context) {
|
func (s *Server) handleGETData(gc *gin.Context) {
|
||||||
|
uidRaw, uidExists := gc.Get("uid")
|
||||||
|
uid, _ := uidRaw.(int64)
|
||||||
accept := gc.GetHeader("Accept")
|
accept := gc.GetHeader("Accept")
|
||||||
if accept == "application/json" {
|
if accept == "application/json" {
|
||||||
data, err := s.getDataOnly()
|
data, err := s.getDataOnly()
|
||||||
@@ -237,7 +345,6 @@ func (s *Server) handleGETData(gc *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
gc.JSON(http.StatusOK, data)
|
gc.JSON(http.StatusOK, data)
|
||||||
return
|
|
||||||
} else if accept == "application/zip" {
|
} else if accept == "application/zip" {
|
||||||
file, err := s.getDataWithPhotos()
|
file, err := s.getDataWithPhotos()
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -260,12 +367,25 @@ func (s *Server) handleGETData(gc *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
gc.DataFromReader(http.StatusOK, size, "application/zip", file, nil)
|
gc.DataFromReader(http.StatusOK, size, "application/zip", file, nil)
|
||||||
|
} else {
|
||||||
|
gc.String(http.StatusNotAcceptable, "%s is not acceptable", accept)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gc.String(http.StatusNotAcceptable, "%s is not acceptable", accept)
|
if uidExists {
|
||||||
|
err := withDbConn(s, func(conn *sqlite.Conn) error {
|
||||||
|
return sqlitex.Execute(conn, "update users set last_download_time = ? where id = ?", &sqlitex.ExecOptions{
|
||||||
|
Args: []interface{}{time.Now().Unix(), uid},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
gc.Error(fmt.Errorf("failed to store last download time: %w", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handlePOSTData(gc *gin.Context) {
|
func (s *Server) handlePOSTData(gc *gin.Context) {
|
||||||
|
uidRaw, uidExists := gc.Get("uid")
|
||||||
|
uid, _ := uidRaw.(int64)
|
||||||
switch gc.ContentType() {
|
switch gc.ContentType() {
|
||||||
case "application/json":
|
case "application/json":
|
||||||
s.handlePOSTDataJSON(gc)
|
s.handlePOSTDataJSON(gc)
|
||||||
@@ -273,6 +393,17 @@ func (s *Server) handlePOSTData(gc *gin.Context) {
|
|||||||
s.handlePOSTDataMultipart(gc)
|
s.handlePOSTDataMultipart(gc)
|
||||||
default:
|
default:
|
||||||
badRequest(gc, fmt.Errorf("unsupported Content-Type"))
|
badRequest(gc, fmt.Errorf("unsupported Content-Type"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if uidExists {
|
||||||
|
err := withDbConn(s, func(conn *sqlite.Conn) error {
|
||||||
|
return sqlitex.Execute(conn, "update users set last_upload_time = ? where id = ?", &sqlitex.ExecOptions{
|
||||||
|
Args: []interface{}{time.Now().Unix(), uid},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
gc.Error(fmt.Errorf("failed to store last upload time: %w", err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,3 +562,12 @@ func (s *Server) handleGETDataProposals(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
gc.JSON(http.StatusOK, proposals)
|
gc.JSON(http.StatusOK, proposals)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleGETUsageInfo(gc *gin.Context) {
|
||||||
|
usage, err := s.getUsageInfo(nil)
|
||||||
|
if err != nil {
|
||||||
|
internalError(gc, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gc.JSON(http.StatusOK, usage)
|
||||||
|
}
|
||||||
|
|||||||
+268
-411
@@ -4,35 +4,30 @@ import (
|
|||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"embed"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"sync/atomic"
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"cernobor.cz/oko-server/errs"
|
"cernobor.cz/oko-server/errs"
|
||||||
"cernobor.cz/oko-server/models"
|
"cernobor.cz/oko-server/models"
|
||||||
"crawshaw.io/sqlite"
|
|
||||||
"crawshaw.io/sqlite/sqlitex"
|
|
||||||
mbsh "github.com/consbio/mbtileserver/handlers"
|
mbsh "github.com/consbio/mbtileserver/handlers"
|
||||||
"github.com/coreos/go-semver/semver"
|
"github.com/coreos/go-semver/semver"
|
||||||
geojson "github.com/paulmach/go.geojson"
|
geojson "github.com/paulmach/go.geojson"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"zombiezen.com/go/sqlite"
|
||||||
|
"zombiezen.com/go/sqlite/sqlitemigration"
|
||||||
|
"zombiezen.com/go/sqlite/sqlitex"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed sql_schema/V*.sql
|
|
||||||
var sqlSchema embed.FS
|
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
config ServerConfig
|
config ServerConfig
|
||||||
dbpool *sqlitex.Pool
|
dbpool *sqlitemigration.Pool
|
||||||
|
dbAvailable atomic.Bool
|
||||||
checkpointNotice chan struct{}
|
checkpointNotice chan struct{}
|
||||||
log *logrus.Logger
|
log *logrus.Logger
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@@ -46,13 +41,12 @@ type ServerConfig struct {
|
|||||||
Port int
|
Port int
|
||||||
DbPath string
|
DbPath string
|
||||||
TilepackPath string
|
TilepackPath string
|
||||||
ApkPath string
|
|
||||||
ReinitDB bool
|
|
||||||
MinZoom int
|
MinZoom int
|
||||||
DefaultCenter models.Coords
|
DefaultCenter models.Coords
|
||||||
MaxPhotoX int
|
MaxPhotoX int
|
||||||
MaxPhotoY int
|
MaxPhotoY int
|
||||||
PhotoQuality int
|
PhotoQuality int
|
||||||
|
Debug bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config ServerConfig) *Server {
|
func New(config ServerConfig) *Server {
|
||||||
@@ -63,10 +57,17 @@ func New(config ServerConfig) *Server {
|
|||||||
|
|
||||||
func (s *Server) Run(ctx context.Context) {
|
func (s *Server) Run(ctx context.Context) {
|
||||||
s.log = logrus.New()
|
s.log = logrus.New()
|
||||||
s.log.SetLevel(logrus.DebugLevel)
|
if s.config.Debug {
|
||||||
|
s.log.SetLevel(logrus.DebugLevel)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.dbAvailable.Store(false)
|
||||||
|
|
||||||
s.ctx = ctx
|
s.ctx = ctx
|
||||||
s.setupDB()
|
err := s.setupDB()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
defer s.cleanupDb()
|
defer s.cleanupDb()
|
||||||
|
|
||||||
s.setupTiles()
|
s.setupTiles()
|
||||||
@@ -95,116 +96,6 @@ func (s *Server) Run(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) cleanupDb() {
|
|
||||||
close(s.checkpointNotice)
|
|
||||||
s.log.Info("Closing db connection pool...")
|
|
||||||
s.dbpool.Close()
|
|
||||||
|
|
||||||
// manually force truncate checkpoint
|
|
||||||
conn, err := sqlite.OpenConn(fmt.Sprintf("file:%s", s.config.DbPath), 0)
|
|
||||||
if err != nil {
|
|
||||||
s.log.WithError(err).Error("Failed to open connection for final checkpoint.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = sqlitex.Exec(conn, "vacuum", nil)
|
|
||||||
if err != nil {
|
|
||||||
s.log.WithError(err).Error("Failed to vacuum db.")
|
|
||||||
}
|
|
||||||
s.checkpointDb(conn, true)
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) getDbConn() *sqlite.Conn {
|
|
||||||
conn := s.dbpool.Get(s.ctx)
|
|
||||||
_, err := conn.Prep("PRAGMA foreign_keys = ON").Step()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return conn
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) checkpointDb(conn *sqlite.Conn, truncate bool) {
|
|
||||||
var query string
|
|
||||||
if truncate {
|
|
||||||
query = "PRAGMA wal_checkpoint(TRUNCATE)"
|
|
||||||
} else {
|
|
||||||
query = "PRAGMA wal_checkpoint(RESTART)"
|
|
||||||
}
|
|
||||||
stmt, _, err := conn.PrepareTransient(query)
|
|
||||||
if err != nil {
|
|
||||||
s.log.WithError(err).Error("Failed to prepare checkpoint query.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer stmt.Finalize()
|
|
||||||
|
|
||||||
has, err := stmt.Step()
|
|
||||||
if err != nil {
|
|
||||||
s.log.WithError(err).Error("Failed to step through checkpoint query.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !has {
|
|
||||||
s.log.Error("Checkpoint query returned no rows.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
blocked := stmt.ColumnInt(0)
|
|
||||||
noWalPages := stmt.ColumnInt(1)
|
|
||||||
noReclaimedPages := stmt.ColumnInt(2)
|
|
||||||
if blocked == 1 {
|
|
||||||
s.log.Warn("Checkpoint query was blocked.")
|
|
||||||
}
|
|
||||||
s.log.Debugf("Checkpoint complete. %d pages written to WAL, %d pages written back to DB.", noWalPages, noReclaimedPages)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) setupDB() {
|
|
||||||
sqlitex.PoolCloseTimeout = time.Second * 10
|
|
||||||
s.log.Debugf("Using db %s", s.config.DbPath)
|
|
||||||
dbpool, err := sqlitex.Open(fmt.Sprintf("file:%s", s.config.DbPath), 0, 10)
|
|
||||||
if err != nil {
|
|
||||||
s.log.WithError(err).Fatal("Failed to open/create DB.")
|
|
||||||
}
|
|
||||||
s.dbpool = dbpool
|
|
||||||
s.checkpointNotice = make(chan struct{})
|
|
||||||
|
|
||||||
err = s.initDB(s.config.ReinitDB)
|
|
||||||
if err != nil {
|
|
||||||
s.log.WithError(err).Fatal("init DB transaction failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// aggressively checkpoint the database on idle times
|
|
||||||
go func() {
|
|
||||||
s.log.Debug("Starting manual restart checkpointing.")
|
|
||||||
defer s.log.Debug("Manual restart checkpointing stopped.")
|
|
||||||
delay := time.Minute * 15
|
|
||||||
var (
|
|
||||||
timer <-chan time.Time
|
|
||||||
ok bool
|
|
||||||
)
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case _, ok = <-s.checkpointNotice:
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
timer = time.After(delay)
|
|
||||||
case <-timer:
|
|
||||||
func() {
|
|
||||||
conn := s.dbpool.Get(s.ctx)
|
|
||||||
defer s.dbpool.Put(conn)
|
|
||||||
s.checkpointDb(conn, false)
|
|
||||||
timer = nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) requestCheckpoint() {
|
|
||||||
go func() {
|
|
||||||
s.checkpointNotice <- struct{}{}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) setupTiles() {
|
func (s *Server) setupTiles() {
|
||||||
tsRootURL, err := url.Parse(URITileserverRoot)
|
tsRootURL, err := url.Parse(URITileserverRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -233,146 +124,6 @@ func (s *Server) setupTiles() {
|
|||||||
s.mapPackSize = info.Size()
|
s.mapPackSize = info.Size()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) initDB(reinit bool) error {
|
|
||||||
s.log.Info("Initializing DB.")
|
|
||||||
conn := s.getDbConn()
|
|
||||||
defer s.dbpool.Put(conn)
|
|
||||||
|
|
||||||
defer s.requestCheckpoint()
|
|
||||||
|
|
||||||
if reinit {
|
|
||||||
s.log.Warn("Reinitializing DB.")
|
|
||||||
tables := []string{}
|
|
||||||
err := sqlitex.Exec(conn, "select name from sqlite_master where type = 'table'", func(stmt *sqlite.Stmt) error {
|
|
||||||
tables = append(tables, stmt.ColumnText(0))
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get table names: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, table := range tables {
|
|
||||||
err = sqlitex.Exec(conn, "drop table "+table, nil)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to drop tables: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sqlitex.Exec(conn, "PRAGMA user_version = 0", nil)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to reset user version: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err := s.migrateDb(conn)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to migrate db: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) migrateDb(conn *sqlite.Conn) error {
|
|
||||||
var version int
|
|
||||||
err := sqlitex.Exec(conn, "PRAGMA user_version", func(stmt *sqlite.Stmt) error {
|
|
||||||
version = stmt.ColumnInt(0)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get user version: %w", err)
|
|
||||||
}
|
|
||||||
s.log.Debugf("Current db version: %d", version)
|
|
||||||
|
|
||||||
entries, err := sqlSchema.ReadDir("sql_schema")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to read sql_schema migrations: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
type migration struct {
|
|
||||||
file string
|
|
||||||
version int
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern := regexp.MustCompile("^V([0-9]+)_(.*)[.][sS][qQ][lL]$")
|
|
||||||
migrations := []migration{}
|
|
||||||
for _, entry := range entries {
|
|
||||||
name := entry.Name()
|
|
||||||
if entry.IsDir() {
|
|
||||||
return fmt.Errorf("embedded sql migration '%s' is a directory", name)
|
|
||||||
}
|
|
||||||
matches := pattern.FindStringSubmatch(name)
|
|
||||||
if matches == nil {
|
|
||||||
return fmt.Errorf("embedded sql migration '%s' does not match the filename pattern", name)
|
|
||||||
}
|
|
||||||
if len(matches) != 3 {
|
|
||||||
return fmt.Errorf("embedded sql migration '%s' does not have the correct number of submatches", name)
|
|
||||||
}
|
|
||||||
version, err := strconv.Atoi(matches[1])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to parse version number of migration '%s': %w", name, err)
|
|
||||||
}
|
|
||||||
migName := matches[2]
|
|
||||||
file := path.Join("sql_schema", name)
|
|
||||||
migrations = append(migrations, migration{
|
|
||||||
file: file,
|
|
||||||
version: version,
|
|
||||||
name: migName,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
sort.Slice(migrations, func(i, j int) bool {
|
|
||||||
return migrations[i].version < migrations[j].version
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, migration := range migrations {
|
|
||||||
if version >= migration.version {
|
|
||||||
s.log.Debugf("Skipping migration version %d because current version %d is not smaller.", migration.version, version)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
migContent, err := sqlSchema.ReadFile(migration.file)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to read embedded migration '%s': %w", migration.file, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = func() (err error) {
|
|
||||||
rollback := sqlitex.Save(conn)
|
|
||||||
defer func() {
|
|
||||||
if err != nil {
|
|
||||||
s.log.Info("Rolling back last migration attempt.")
|
|
||||||
}
|
|
||||||
rollback(&err)
|
|
||||||
}()
|
|
||||||
|
|
||||||
s.log.Infof("Executing migration V%d - %s", migration.version, migration.name)
|
|
||||||
err = sqlitex.ExecScript(conn, string(migContent))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to execute migration '%s': %w", migration.name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sqlitex.Exec(conn, fmt.Sprintf("PRAGMA user_version = %d", migration.version), nil)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to set user_version in db: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sqlitex.Exec(conn, "PRAGMA user_version", func(stmt *sqlite.Stmt) error {
|
|
||||||
version = stmt.ColumnInt(0)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get user_version: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.log.Infof("Migrated db to version: %d", version)
|
|
||||||
return nil
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) getLatestVersion(v *semver.Version) (*models.AppVersionInfo, error) {
|
func (s *Server) getLatestVersion(v *semver.Version) (*models.AppVersionInfo, error) {
|
||||||
conn := s.getDbConn()
|
conn := s.getDbConn()
|
||||||
defer s.dbpool.Put(conn)
|
defer s.dbpool.Put(conn)
|
||||||
@@ -397,20 +148,22 @@ func (s *Server) getAppVersions() ([]*models.AppVersionInfo, error) {
|
|||||||
defer s.dbpool.Put(conn)
|
defer s.dbpool.Put(conn)
|
||||||
|
|
||||||
versions := []*models.AppVersionInfo{}
|
versions := []*models.AppVersionInfo{}
|
||||||
err := sqlitex.Exec(conn, "select version, address from app_versions", func(stmt *sqlite.Stmt) error {
|
err := sqlitex.Execute(conn, "select version, address from app_versions", &sqlitex.ExecOptions{
|
||||||
verStr := stmt.ColumnText(0)
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
addr := stmt.ColumnText(1)
|
verStr := stmt.ColumnText(0)
|
||||||
|
addr := stmt.ColumnText(1)
|
||||||
|
|
||||||
ver, err := semver.NewVersion(verStr)
|
ver, err := semver.NewVersion(verStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse version: %w", err)
|
return fmt.Errorf("failed to parse version: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
versions = append(versions, &models.AppVersionInfo{
|
versions = append(versions, &models.AppVersionInfo{
|
||||||
Version: *ver,
|
Version: *ver,
|
||||||
Address: addr,
|
Address: addr,
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to insert/retrieve user from db: %w", err)
|
return nil, fmt.Errorf("failed to insert/retrieve user from db: %w", err)
|
||||||
@@ -423,7 +176,9 @@ func (s *Server) putAppVersion(versionInfo *models.AppVersionInfo) error {
|
|||||||
conn := s.getDbConn()
|
conn := s.getDbConn()
|
||||||
defer s.dbpool.Put(conn)
|
defer s.dbpool.Put(conn)
|
||||||
|
|
||||||
err := sqlitex.Exec(conn, "insert into app_versions(version, address) values(?, ?) on conflict(version) do update set address = excluded.address", nil, versionInfo.Version.String(), versionInfo.Address)
|
err := sqlitex.Execute(conn, "insert into app_versions(version, address) values(?, ?) on conflict(version) do update set address = excluded.address", &sqlitex.ExecOptions{
|
||||||
|
Args: []interface{}{versionInfo.Version.String(), versionInfo.Address},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to insert app version into db: %w", err)
|
return fmt.Errorf("failed to insert app version into db: %w", err)
|
||||||
}
|
}
|
||||||
@@ -431,6 +186,49 @@ func (s *Server) putAppVersion(versionInfo *models.AppVersionInfo) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) getAppVersion(version string) (*models.AppVersionInfo, error) {
|
||||||
|
conn := s.getDbConn()
|
||||||
|
defer s.dbpool.Put(conn)
|
||||||
|
|
||||||
|
var v *models.AppVersionInfo
|
||||||
|
err := sqlitex.Execute(conn, "select version, address from app_versions where version = ?", &sqlitex.ExecOptions{
|
||||||
|
Args: []interface{}{version},
|
||||||
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
|
verStr := stmt.ColumnText(0)
|
||||||
|
ver, err := semver.NewVersion(verStr)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to parse version string %s from db: %w", verStr, err)
|
||||||
|
}
|
||||||
|
addr := stmt.ColumnText(1)
|
||||||
|
v = &models.AppVersionInfo{
|
||||||
|
Version: *ver,
|
||||||
|
Address: addr,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to retrieve app version %s from db: %w", version, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) deleteAppVersion(version string) (bool, error) {
|
||||||
|
conn := s.getDbConn()
|
||||||
|
defer s.dbpool.Put(conn)
|
||||||
|
|
||||||
|
err := sqlitex.Execute(conn, "delete from app_versions where version = ?", &sqlitex.ExecOptions{
|
||||||
|
Args: []interface{}{version},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("failed to delete app version %s from db: %w", version, err)
|
||||||
|
}
|
||||||
|
n := conn.Changes()
|
||||||
|
|
||||||
|
return n > 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) handshake(hc models.HandshakeChallenge) (models.UserID, error) {
|
func (s *Server) handshake(hc models.HandshakeChallenge) (models.UserID, error) {
|
||||||
conn := s.getDbConn()
|
conn := s.getDbConn()
|
||||||
defer s.dbpool.Put(conn)
|
defer s.dbpool.Put(conn)
|
||||||
@@ -440,11 +238,14 @@ func (s *Server) handshake(hc models.HandshakeChallenge) (models.UserID, error)
|
|||||||
|
|
||||||
var id *int64
|
var id *int64
|
||||||
if hc.Exists {
|
if hc.Exists {
|
||||||
err = sqlitex.Exec(conn, "select id from users where name = ?", func(stmt *sqlite.Stmt) error {
|
err = sqlitex.Execute(conn, "select id from users where name = ?", &sqlitex.ExecOptions{
|
||||||
id = ptr(stmt.ColumnInt64(0))
|
Args: []interface{}{hc.Name},
|
||||||
return nil
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
}, hc.Name)
|
id = ptr(stmt.ColumnInt64(0))
|
||||||
if sqlite.ErrCode(err) != sqlite.SQLITE_OK {
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if sqlite.ErrCode(err) != sqlite.ResultOK {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if id == nil {
|
if id == nil {
|
||||||
@@ -454,14 +255,17 @@ func (s *Server) handshake(hc models.HandshakeChallenge) (models.UserID, error)
|
|||||||
return 0, errs.ErrAttemptedSystemUser
|
return 0, errs.ErrAttemptedSystemUser
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = sqlitex.Exec(conn, "insert into users(name) values(?)", func(stmt *sqlite.Stmt) error {
|
err = sqlitex.Execute(conn, "insert into users(name) values(?)", &sqlitex.ExecOptions{
|
||||||
id = ptr(stmt.ColumnInt64(0))
|
Args: []interface{}{hc.Name},
|
||||||
return nil
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
}, hc.Name)
|
id = ptr(stmt.ColumnInt64(0))
|
||||||
if sqlite.ErrCode(err) == sqlite.SQLITE_CONSTRAINT_UNIQUE {
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if sqlite.ErrCode(err) == sqlite.ResultConstraintUnique {
|
||||||
return 0, errs.ErrUserAlreadyExists
|
return 0, errs.ErrUserAlreadyExists
|
||||||
}
|
}
|
||||||
if sqlite.ErrCode(err) != sqlite.SQLITE_OK {
|
if sqlite.ErrCode(err) != sqlite.ResultOK {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
id = ptr(conn.LastInsertRowID())
|
id = ptr(conn.LastInsertRowID())
|
||||||
@@ -489,10 +293,15 @@ func (s *Server) getData(conn *sqlite.Conn) (data models.Data, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return models.Data{}, fmt.Errorf("failed to retreive features: %w", err)
|
return models.Data{}, fmt.Errorf("failed to retreive features: %w", err)
|
||||||
}
|
}
|
||||||
|
proposals, err := s.getProposals(conn)
|
||||||
|
if err != nil {
|
||||||
|
return models.Data{}, fmt.Errorf("failed to retrieve proposals: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return models.Data{
|
return models.Data{
|
||||||
Users: people,
|
Users: people,
|
||||||
Features: features,
|
Features: features,
|
||||||
|
Proposals: proposals,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,17 +336,19 @@ func (s *Server) getDataWithPhotos() (file *os.File, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data.PhotoMetadata = make(map[string]models.PhotoMetadata, 100)
|
data.PhotoMetadata = make(map[string]models.PhotoMetadata, 100)
|
||||||
err = sqlitex.Exec(conn, "select id, content_type, length(contents) from feature_photos", func(stmt *sqlite.Stmt) error {
|
err = sqlitex.Execute(conn, "select id, content_type, length(contents) from feature_photos", &sqlitex.ExecOptions{
|
||||||
id := models.FeaturePhotoID(stmt.ColumnInt64(0))
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
contentType := stmt.ColumnText(1)
|
id := models.FeaturePhotoID(stmt.ColumnInt64(0))
|
||||||
fileSize := stmt.ColumnInt64(2)
|
contentType := stmt.ColumnText(1)
|
||||||
data.PhotoMetadata[makePhotoFilename(id)] = models.PhotoMetadata{
|
fileSize := stmt.ColumnInt64(2)
|
||||||
ContentType: contentType,
|
data.PhotoMetadata[makePhotoFilename(id)] = models.PhotoMetadata{
|
||||||
Size: fileSize,
|
ContentType: contentType,
|
||||||
ID: id,
|
Size: fileSize,
|
||||||
ThumbnailFilename: makeThumbnailFilename(id),
|
ID: id,
|
||||||
}
|
ThumbnailFilename: makeThumbnailFilename(id),
|
||||||
return nil
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to collect photo metadata: %w", err)
|
return nil, fmt.Errorf("failed to collect photo metadata: %w", err)
|
||||||
@@ -564,50 +375,52 @@ func (s *Server) getDataWithPhotos() (file *os.File, err error) {
|
|||||||
return nil, fmt.Errorf("failed to write data zip entry: %w", err)
|
return nil, fmt.Errorf("failed to write data zip entry: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sqlitex.Exec(conn, "select id from feature_photos fp where exists (select 1 from features f where f.id = fp.feature_id)", func(stmt *sqlite.Stmt) error {
|
err = sqlitex.Execute(conn, "select id from feature_photos fp where exists (select 1 from features f where f.id = fp.feature_id)", &sqlitex.ExecOptions{
|
||||||
id := stmt.ColumnInt64(0)
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
|
id := stmt.ColumnInt64(0)
|
||||||
|
|
||||||
blob, err := conn.OpenBlob("", "feature_photos", "thumbnail_contents", id, false)
|
blob, err := conn.OpenBlob("", "feature_photos", "thumbnail_contents", id, false)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to open photo ID %d thumbnail content blob: %w", id, err)
|
|
||||||
}
|
|
||||||
err = func() error {
|
|
||||||
defer blob.Close()
|
|
||||||
w, err := zw.Create(makeThumbnailFilename(models.FeaturePhotoID(id)))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create zip entry: %w", err)
|
return fmt.Errorf("failed to open photo ID %d thumbnail content blob: %w", id, err)
|
||||||
}
|
}
|
||||||
_, err = io.Copy(w, blob)
|
err = func() error {
|
||||||
|
defer blob.Close()
|
||||||
|
w, err := zw.Create(makeThumbnailFilename(models.FeaturePhotoID(id)))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create zip entry: %w", err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(w, blob)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write zip entry: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to write zip entry: %w", err)
|
return fmt.Errorf("failed to write photo ID %d thumbnail: %w", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blob, err = conn.OpenBlob("", "feature_photos", "contents", id, false)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to open photo ID %d photo content blob: %w", id, err)
|
||||||
|
}
|
||||||
|
err = func() error {
|
||||||
|
defer blob.Close()
|
||||||
|
w, err := zw.Create(makePhotoFilename(models.FeaturePhotoID(id)))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create zip entry: %w", err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(w, blob)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write zip entry: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write photo ID %d photo: %w", id, err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}()
|
},
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to write photo ID %d thumbnail: %w", id, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
blob, err = conn.OpenBlob("", "feature_photos", "contents", id, false)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to open photo ID %d photo content blob: %w", id, err)
|
|
||||||
}
|
|
||||||
err = func() error {
|
|
||||||
defer blob.Close()
|
|
||||||
w, err := zw.Create(makePhotoFilename(models.FeaturePhotoID(id)))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create zip entry: %w", err)
|
|
||||||
}
|
|
||||||
_, err = io.Copy(w, blob)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to write zip entry: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to write photo ID %d photo: %w", id, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to collect photo files: %w", err)
|
return nil, fmt.Errorf("failed to collect photo files: %w", err)
|
||||||
@@ -622,7 +435,7 @@ func (s *Server) update(data models.Update, photos map[string]models.Photo) erro
|
|||||||
defer s.dbpool.Put(conn)
|
defer s.dbpool.Put(conn)
|
||||||
|
|
||||||
return func() (err error) {
|
return func() (err error) {
|
||||||
defer sqlitex.Save(conn)(&err)
|
defer sqlitex.Transaction(conn)(&err)
|
||||||
|
|
||||||
var createdIDMapping map[models.FeatureID]models.FeatureID
|
var createdIDMapping map[models.FeatureID]models.FeatureID
|
||||||
if data.Create != nil {
|
if data.Create != nil {
|
||||||
@@ -677,14 +490,10 @@ func (s *Server) update(data models.Update, photos map[string]models.Photo) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) deleteExpiredFeatures(conn *sqlite.Conn) error {
|
func (s *Server) deleteExpiredFeatures(conn *sqlite.Conn) error {
|
||||||
stmt, err := conn.Prepare("delete from features where deadline < ?")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to prepare statement: %w", err)
|
|
||||||
}
|
|
||||||
defer stmt.Finalize()
|
|
||||||
|
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
err = sqlitex.Exec(conn, "delete from features where deadline < ?", func(stmt *sqlite.Stmt) error { return nil }, now)
|
err := sqlitex.Execute(conn, "delete from features where deadline < ?", &sqlitex.ExecOptions{
|
||||||
|
Args: []interface{}{now},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to delete expired features: %w", err)
|
return fmt.Errorf("failed to delete expired features: %w", err)
|
||||||
}
|
}
|
||||||
@@ -695,16 +504,18 @@ func (s *Server) deleteExpiredFeatures(conn *sqlite.Conn) error {
|
|||||||
func (s *Server) getPeople(conn *sqlite.Conn) ([]models.User, error) {
|
func (s *Server) getPeople(conn *sqlite.Conn) ([]models.User, error) {
|
||||||
if conn == nil {
|
if conn == nil {
|
||||||
conn = s.getDbConn()
|
conn = s.getDbConn()
|
||||||
defer s.dbpool.Put(conn)
|
defer s.returnDbConn(conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
users := make([]models.User, 0, 50)
|
users := make([]models.User, 0, 50)
|
||||||
err := sqlitex.Exec(conn, "select id, name from users", func(stmt *sqlite.Stmt) error {
|
err := sqlitex.Execute(conn, "select id, name from users", &sqlitex.ExecOptions{
|
||||||
users = append(users, models.User{
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
ID: models.UserID(stmt.ColumnInt(0)),
|
users = append(users, models.User{
|
||||||
Name: stmt.ColumnText(1),
|
ID: models.UserID(stmt.ColumnInt(0)),
|
||||||
})
|
Name: stmt.ColumnText(1),
|
||||||
return nil
|
})
|
||||||
|
return nil
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get users from db: %w", err)
|
return nil, fmt.Errorf("failed to get users from db: %w", err)
|
||||||
@@ -719,56 +530,58 @@ func (s *Server) getFeatures(conn *sqlite.Conn) ([]models.Feature, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
features := make([]models.Feature, 0, 100)
|
features := make([]models.Feature, 0, 100)
|
||||||
err := sqlitex.Exec(conn, `select f.id, f.owner_id, f.name, f.deadline, f.properties, f.geom, '[' || coalesce(group_concat(p.id, ', '), '') || ']'
|
err := sqlitex.Execute(conn, `select f.id, f.owner_id, f.name, f.deadline, f.properties, f.geom, '[' || coalesce(group_concat(p.id, ', '), '') || ']'
|
||||||
from features f
|
from features f
|
||||||
left join feature_photos p on f.id = p.feature_id
|
left join feature_photos p on f.id = p.feature_id
|
||||||
group by f.id, f.owner_id, f.name, f.properties, f.geom`, func(stmt *sqlite.Stmt) error {
|
group by f.id, f.owner_id, f.name, f.properties, f.geom`, &sqlitex.ExecOptions{
|
||||||
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
|
|
||||||
id := stmt.ColumnInt64(0)
|
id := stmt.ColumnInt64(0)
|
||||||
|
|
||||||
ownerID := stmt.ColumnInt64(1)
|
ownerID := stmt.ColumnInt64(1)
|
||||||
|
|
||||||
name := stmt.ColumnText(2)
|
name := stmt.ColumnText(2)
|
||||||
|
|
||||||
var deadline *time.Time
|
var deadline *time.Time
|
||||||
if stmt.ColumnType(3) != sqlite.SQLITE_NULL {
|
if stmt.ColumnType(3) != sqlite.TypeNull {
|
||||||
dl := time.Unix(stmt.ColumnInt64(3), 0)
|
dl := time.Unix(stmt.ColumnInt64(3), 0)
|
||||||
deadline = &dl
|
deadline = &dl
|
||||||
}
|
}
|
||||||
|
|
||||||
propertiesRaw := stmt.ColumnText(4)
|
propertiesRaw := stmt.ColumnText(4)
|
||||||
var properties map[string]interface{}
|
var properties map[string]interface{}
|
||||||
err := json.Unmarshal([]byte(propertiesRaw), &properties)
|
err := json.Unmarshal([]byte(propertiesRaw), &properties)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse properties for feature id=%d: %w", id, err)
|
return fmt.Errorf("failed to parse properties for feature id=%d: %w", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
geomRaw := stmt.ColumnText(5)
|
geomRaw := stmt.ColumnText(5)
|
||||||
var geom geojson.Geometry
|
var geom geojson.Geometry
|
||||||
err = json.Unmarshal([]byte(geomRaw), &geom)
|
err = json.Unmarshal([]byte(geomRaw), &geom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse geometry for feature id=%d: %w", id, err)
|
return fmt.Errorf("failed to parse geometry for feature id=%d: %w", id, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
photosRaw := stmt.ColumnText(6)
|
photosRaw := stmt.ColumnText(6)
|
||||||
var photos []models.FeaturePhotoID
|
var photos []models.FeaturePhotoID
|
||||||
err = json.Unmarshal([]byte(photosRaw), &photos)
|
err = json.Unmarshal([]byte(photosRaw), &photos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse list of photo IDs: %w", err)
|
return fmt.Errorf("failed to parse list of photo IDs: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
feature := models.Feature{
|
feature := models.Feature{
|
||||||
ID: models.FeatureID(id),
|
ID: models.FeatureID(id),
|
||||||
OwnerID: models.UserID(ownerID),
|
OwnerID: models.UserID(ownerID),
|
||||||
Name: name,
|
Name: name,
|
||||||
Deadline: deadline,
|
Deadline: deadline,
|
||||||
Properties: properties,
|
Properties: properties,
|
||||||
Geometry: geom,
|
Geometry: geom,
|
||||||
PhotoIDs: photos,
|
PhotoIDs: photos,
|
||||||
}
|
}
|
||||||
|
|
||||||
features = append(features, feature)
|
features = append(features, feature)
|
||||||
return nil
|
return nil
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get users from db: %w", err)
|
return nil, fmt.Errorf("failed to get users from db: %w", err)
|
||||||
@@ -1062,16 +875,19 @@ func (s *Server) getPhoto(featureID models.FeatureID, photoID models.FeaturePhot
|
|||||||
var contentType *string = nil
|
var contentType *string = nil
|
||||||
var data []byte = nil
|
var data []byte = nil
|
||||||
found := false
|
found := false
|
||||||
err := sqlitex.Exec(conn, "select content_type, contents from feature_photos where id = ? and feature_id = ?", func(stmt *sqlite.Stmt) error {
|
err := sqlitex.Execute(conn, "select content_type, contents from feature_photos where id = ? and feature_id = ?", &sqlitex.ExecOptions{
|
||||||
if found {
|
Args: []interface{}{photoID, featureID},
|
||||||
return fmt.Errorf("multiple photos returned for feature id %d, photo id %d", featureID, photoID)
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
}
|
if found {
|
||||||
contentType = ptr(stmt.ColumnText(0))
|
return fmt.Errorf("multiple photos returned for feature id %d, photo id %d", featureID, photoID)
|
||||||
data = make([]byte, stmt.ColumnLen(1))
|
}
|
||||||
stmt.ColumnBytes(1, data)
|
contentType = ptr(stmt.ColumnText(0))
|
||||||
found = true
|
data = make([]byte, stmt.ColumnLen(1))
|
||||||
return nil
|
stmt.ColumnBytes(1, data)
|
||||||
}, photoID, featureID)
|
found = true
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", fmt.Errorf("photo db query failed: %w", err)
|
return nil, "", fmt.Errorf("photo db query failed: %w", err)
|
||||||
}
|
}
|
||||||
@@ -1120,16 +936,57 @@ func (s *Server) getProposals(conn *sqlite.Conn) ([]models.Proposal, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
proposals := make([]models.Proposal, 0, 100)
|
proposals := make([]models.Proposal, 0, 100)
|
||||||
err := sqlitex.Exec(conn, "select owner_id, description, how from proposals", func(stmt *sqlite.Stmt) error {
|
err := sqlitex.Execute(conn, "select owner_id, description, how from proposals", &sqlitex.ExecOptions{
|
||||||
proposals = append(proposals, models.Proposal{
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
OwnerID: models.UserID(stmt.ColumnInt(0)),
|
proposals = append(proposals, models.Proposal{
|
||||||
Description: stmt.ColumnText(1),
|
OwnerID: models.UserID(stmt.ColumnInt(0)),
|
||||||
How: stmt.ColumnText(2),
|
Description: stmt.ColumnText(1),
|
||||||
})
|
How: stmt.ColumnText(2),
|
||||||
return nil
|
})
|
||||||
|
return nil
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to get proposals from db: %w", err)
|
return nil, fmt.Errorf("failed to get proposals from db: %w", err)
|
||||||
}
|
}
|
||||||
return proposals, nil
|
return proposals, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) getUsageInfo(conn *sqlite.Conn) ([]models.UserInfo, error) {
|
||||||
|
if conn == nil {
|
||||||
|
conn = s.getDbConn()
|
||||||
|
defer s.returnDbConn(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
users := make([]models.UserInfo, 0, 50)
|
||||||
|
err := sqlitex.Execute(conn, "select id, name, app_version, last_seen_time, last_upload_time, last_download_time from users", &sqlitex.ExecOptions{
|
||||||
|
ResultFunc: func(stmt *sqlite.Stmt) error {
|
||||||
|
ver, _ := semver.NewVersion(stmt.ColumnText(2))
|
||||||
|
var lstp, lutp, ldtp *time.Time
|
||||||
|
if stmt.ColumnType(3) != sqlite.TypeNull {
|
||||||
|
lstp = ptr(time.Unix(stmt.ColumnInt64(3), 0))
|
||||||
|
}
|
||||||
|
if stmt.ColumnType(4) != sqlite.TypeNull {
|
||||||
|
lutp = ptr(time.Unix(stmt.ColumnInt64(3), 0))
|
||||||
|
}
|
||||||
|
if stmt.ColumnType(5) != sqlite.TypeNull {
|
||||||
|
ldtp = ptr(time.Unix(stmt.ColumnInt64(3), 0))
|
||||||
|
}
|
||||||
|
users = append(users, models.UserInfo{
|
||||||
|
User: models.User{
|
||||||
|
ID: models.UserID(stmt.ColumnInt(0)),
|
||||||
|
Name: stmt.ColumnText(1),
|
||||||
|
},
|
||||||
|
AppVersion: ver,
|
||||||
|
LastSeenTime: lstp,
|
||||||
|
LastUploadTime: lutp,
|
||||||
|
LastDownloadTime: ldtp,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get users from db: %w", err)
|
||||||
|
}
|
||||||
|
return users, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ CREATE TABLE features (
|
|||||||
id integer PRIMARY KEY AUTOINCREMENT,
|
id integer PRIMARY KEY AUTOINCREMENT,
|
||||||
owner_id integer NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
owner_id integer NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
name text NOT NULL,
|
name text NOT NULL,
|
||||||
deadline text,
|
deadline integer,
|
||||||
properties text NOT NULL,
|
properties text NOT NULL,
|
||||||
geom text NOT NULL
|
geom text NOT NULL
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
ALTER TABLE users ADD COLUMN app_version text;
|
||||||
|
ALTER TABLE users ADD COLUMN last_seen_time integer;
|
||||||
|
ALTER TABLE users ADD COLUMN last_upload_time integer;
|
||||||
|
ALTER TABLE users ADD COLUMN last_download_time integer;
|
||||||
@@ -17,6 +17,14 @@ func ptr[T any](x T) *T {
|
|||||||
return &x
|
return &x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Map[T any, U any](f func(T) U, x []T) []U {
|
||||||
|
res := make([]U, len(x))
|
||||||
|
for i, e := range x {
|
||||||
|
res[i] = f(e)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
var contentTypes map[string]struct{} = map[string]struct{}{"image/jpeg": {}, "image/png": {}}
|
var contentTypes map[string]struct{} = map[string]struct{}{"image/jpeg": {}, "image/png": {}}
|
||||||
|
|
||||||
func checkImageContentType(contentType string) bool {
|
func checkImageContentType(contentType string) bool {
|
||||||
|
|||||||
Reference in New Issue
Block a user