handle exceptions gracefuly in rest api (#617)

This commit is contained in:
Dmitriy Ryajov 2023-11-14 13:05:43 -06:00 committed by GitHub
parent 8d61391073
commit 4d50ecf504
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 126 additions and 91 deletions

View File

@ -160,26 +160,33 @@ proc initSalesApi(node: CodexNodeRef, router: var RestRouter) =
MethodGet, MethodGet,
"/api/codex/v1/sales/slots") do () -> RestApiResponse: "/api/codex/v1/sales/slots") do () -> RestApiResponse:
## Returns active slots for the host ## Returns active slots for the host
try:
without contracts =? node.contracts.host:
return RestApiResponse.error(Http503, "Sales unavailable")
without contracts =? node.contracts.host: let json = %(await contracts.sales.mySlots())
return RestApiResponse.error(Http503, "Sales unavailable") return RestApiResponse.response($json, contentType="application/json")
except CatchableError as exc:
let json = %(await contracts.sales.mySlots()) trace "Excepting processing request", exc = exc.msg
return RestApiResponse.response($json, contentType="application/json") return RestApiResponse.error(Http500)
router.api( router.api(
MethodGet, MethodGet,
"/api/codex/v1/sales/availability") do () -> RestApiResponse: "/api/codex/v1/sales/availability") do () -> RestApiResponse:
## Returns storage that is for sale ## Returns storage that is for sale
without contracts =? node.contracts.host: try:
return RestApiResponse.error(Http503, "Sales unavailable") without contracts =? node.contracts.host:
return RestApiResponse.error(Http503, "Sales unavailable")
without avails =? (await contracts.sales.context.reservations.all(Availability)), err: without avails =? (await contracts.sales.context.reservations.all(Availability)), err:
return RestApiResponse.error(Http500, err.msg) return RestApiResponse.error(Http500, err.msg)
let json = %avails let json = %avails
return RestApiResponse.response($json, contentType="application/json") return RestApiResponse.response($json, contentType="application/json")
except CatchableError as exc:
trace "Excepting processing request", exc = exc.msg
return RestApiResponse.error(Http500)
router.rawApi( router.rawApi(
MethodPost, MethodPost,
@ -191,30 +198,34 @@ proc initSalesApi(node: CodexNodeRef, router: var RestRouter) =
## minPrice - minimum price to be paid (in amount of tokens) ## minPrice - minimum price to be paid (in amount of tokens)
## maxCollateral - maximum collateral user is willing to pay per filled Slot (in amount of tokens) ## maxCollateral - maximum collateral user is willing to pay per filled Slot (in amount of tokens)
without contracts =? node.contracts.host: try:
return RestApiResponse.error(Http503, "Sales unavailable") without contracts =? node.contracts.host:
return RestApiResponse.error(Http503, "Sales unavailable")
let body = await request.getBody() let body = await request.getBody()
without restAv =? RestAvailability.fromJson(body), error: without restAv =? RestAvailability.fromJson(body), error:
return RestApiResponse.error(Http400, error.msg) return RestApiResponse.error(Http400, error.msg)
let reservations = contracts.sales.context.reservations let reservations = contracts.sales.context.reservations
if not reservations.hasAvailable(restAv.size.truncate(uint)): if not reservations.hasAvailable(restAv.size.truncate(uint)):
return RestApiResponse.error(Http422, "Not enough storage quota") return RestApiResponse.error(Http422, "Not enough storage quota")
without availability =? ( without availability =? (
await reservations.createAvailability( await reservations.createAvailability(
restAv.size, restAv.size,
restAv.duration, restAv.duration,
restAv.minPrice, restAv.minPrice,
restAv.maxCollateral) restAv.maxCollateral)
), error: ), error:
return RestApiResponse.error(Http500, error.msg) return RestApiResponse.error(Http500, error.msg)
return RestApiResponse.response(availability.toJson, return RestApiResponse.response(availability.toJson,
contentType="application/json") contentType="application/json")
except CatchableError as exc:
trace "Excepting processing request", exc = exc.msg
return RestApiResponse.error(Http500)
proc initPurchasingApi(node: CodexNodeRef, router: var RestRouter) = proc initPurchasingApi(node: CodexNodeRef, router: var RestRouter) =
router.rawApi( router.rawApi(
@ -231,62 +242,74 @@ proc initPurchasingApi(node: CodexNodeRef, router: var RestRouter) =
## tolerance - allowed number of nodes that can be lost before pronouncing the content lost ## tolerance - allowed number of nodes that can be lost before pronouncing the content lost
## colateral - requested collateral from hosts when they fill slot ## colateral - requested collateral from hosts when they fill slot
without cid =? cid.tryGet.catch, error: try:
return RestApiResponse.error(Http400, error.msg) without cid =? cid.tryGet.catch, error:
return RestApiResponse.error(Http400, error.msg)
let body = await request.getBody() let body = await request.getBody()
without params =? StorageRequestParams.fromJson(body), error: without params =? StorageRequestParams.fromJson(body), error:
return RestApiResponse.error(Http400, error.msg) return RestApiResponse.error(Http400, error.msg)
let nodes = params.nodes |? 1 let nodes = params.nodes |? 1
let tolerance = params.tolerance |? 0 let tolerance = params.tolerance |? 0
without purchaseId =? await node.requestStorage( without purchaseId =? await node.requestStorage(
cid, cid,
params.duration, params.duration,
params.proofProbability, params.proofProbability,
nodes, nodes,
tolerance, tolerance,
params.reward, params.reward,
params.collateral, params.collateral,
params.expiry), error: params.expiry), error:
return RestApiResponse.error(Http500, error.msg) return RestApiResponse.error(Http500, error.msg)
return RestApiResponse.response(purchaseId.toHex) return RestApiResponse.response(purchaseId.toHex)
except CatchableError as exc:
trace "Excepting processing request", exc = exc.msg
return RestApiResponse.error(Http500)
router.api( router.api(
MethodGet, MethodGet,
"/api/codex/v1/storage/purchases/{id}") do ( "/api/codex/v1/storage/purchases/{id}") do (
id: PurchaseId) -> RestApiResponse: id: PurchaseId) -> RestApiResponse:
without contracts =? node.contracts.client: try:
return RestApiResponse.error(Http503, "Purchasing unavailable") without contracts =? node.contracts.client:
return RestApiResponse.error(Http503, "Purchasing unavailable")
without id =? id.tryGet.catch, error: without id =? id.tryGet.catch, error:
return RestApiResponse.error(Http400, error.msg) return RestApiResponse.error(Http400, error.msg)
without purchase =? contracts.purchasing.getPurchase(id): without purchase =? contracts.purchasing.getPurchase(id):
return RestApiResponse.error(Http404) return RestApiResponse.error(Http404)
let json = % RestPurchase( let json = % RestPurchase(
state: purchase.state |? "none", state: purchase.state |? "none",
error: purchase.error.?msg, error: purchase.error.?msg,
request: purchase.request, request: purchase.request,
requestId: purchase.requestId requestId: purchase.requestId
) )
return RestApiResponse.response($json, contentType="application/json") return RestApiResponse.response($json, contentType="application/json")
except CatchableError as exc:
trace "Excepting processing request", exc = exc.msg
return RestApiResponse.error(Http500)
router.api( router.api(
MethodGet, MethodGet,
"/api/codex/v1/storage/purchases") do () -> RestApiResponse: "/api/codex/v1/storage/purchases") do () -> RestApiResponse:
without contracts =? node.contracts.client: try:
return RestApiResponse.error(Http503, "Purchasing unavailable") without contracts =? node.contracts.client:
return RestApiResponse.error(Http503, "Purchasing unavailable")
let purchaseIds = contracts.purchasing.getPurchaseIds() let purchaseIds = contracts.purchasing.getPurchaseIds()
return RestApiResponse.response($ %purchaseIds, contentType="application/json") return RestApiResponse.response($ %purchaseIds, contentType="application/json")
except CatchableError as exc:
trace "Excepting processing request", exc = exc.msg
return RestApiResponse.error(Http500)
proc initDebugApi(node: CodexNodeRef, conf: CodexConf, router: var RestRouter) = proc initDebugApi(node: CodexNodeRef, conf: CodexConf, router: var RestRouter) =
router.api( router.api(
@ -295,27 +318,31 @@ proc initDebugApi(node: CodexNodeRef, conf: CodexConf, router: var RestRouter) =
## Print rudimentary node information ## Print rudimentary node information
## ##
let table = RestRoutingTable.init(node.discovery.protocol.routingTable) try:
let table = RestRoutingTable.init(node.discovery.protocol.routingTable)
let let
json = %*{ json = %*{
"id": $node.switch.peerInfo.peerId, "id": $node.switch.peerInfo.peerId,
"addrs": node.switch.peerInfo.addrs.mapIt( $it ), "addrs": node.switch.peerInfo.addrs.mapIt( $it ),
"repo": $conf.dataDir, "repo": $conf.dataDir,
"spr": "spr":
if node.discovery.dhtRecord.isSome: if node.discovery.dhtRecord.isSome:
node.discovery.dhtRecord.get.toURI node.discovery.dhtRecord.get.toURI
else: else:
"", "",
"announceAddresses": node.discovery.announceAddrs, "announceAddresses": node.discovery.announceAddrs,
"table": table, "table": table,
"codex": { "codex": {
"version": $codexVersion, "version": $codexVersion,
"revision": $codexRevision "revision": $codexRevision
}
} }
}
return RestApiResponse.response($json, contentType="application/json") return RestApiResponse.response($json, contentType="application/json")
except CatchableError as exc:
trace "Excepting processing request", exc = exc.msg
return RestApiResponse.error(Http500)
router.api( router.api(
MethodPost, MethodPost,
@ -328,22 +355,27 @@ proc initDebugApi(node: CodexNodeRef, conf: CodexConf, router: var RestRouter) =
## `level` - chronicles log level ## `level` - chronicles log level
## ##
without res =? level and level =? res:
return RestApiResponse.error(Http400, "Missing log level")
try: try:
{.gcsafe.}: without res =? level and level =? res:
updateLogLevel(level) return RestApiResponse.error(Http400, "Missing log level")
except CatchableError as exc:
return RestApiResponse.error(Http500, exc.msg)
return RestApiResponse.response("") try:
{.gcsafe.}:
updateLogLevel(level)
except CatchableError as exc:
return RestApiResponse.error(Http500, exc.msg)
return RestApiResponse.response("")
except CatchableError as exc:
trace "Excepting processing request", exc = exc.msg
return RestApiResponse.error(Http500)
when codex_enable_api_debug_peers: when codex_enable_api_debug_peers:
router.api( router.api(
MethodGet, MethodGet,
"/api/codex/v1/debug/peer/{peerId}") do (peerId: PeerId) -> RestApiResponse: "/api/codex/v1/debug/peer/{peerId}") do (peerId: PeerId) -> RestApiResponse:
try:
trace "debug/peer start" trace "debug/peer start"
without peerRecord =? (await node.findPeer(peerId.get())): without peerRecord =? (await node.findPeer(peerId.get())):
trace "debug/peer peer not found!" trace "debug/peer peer not found!"
@ -354,6 +386,9 @@ proc initDebugApi(node: CodexNodeRef, conf: CodexConf, router: var RestRouter) =
let json = %RestPeerRecord.init(peerRecord) let json = %RestPeerRecord.init(peerRecord)
trace "debug/peer returning peer record" trace "debug/peer returning peer record"
return RestApiResponse.response($json) return RestApiResponse.response($json)
except CatchableError as exc:
trace "Excepting processing request", exc = exc.msg
return RestApiResponse.error(Http500)
proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter = proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter =
var router = RestRouter.init(validate) var router = RestRouter.init(validate)
@ -397,6 +432,6 @@ proc initRestApi*(node: CodexNodeRef, conf: CodexConf): RestRouter =
except DialFailedError: except DialFailedError:
return RestApiResponse.error(Http400, "Unable to dial peer") return RestApiResponse.error(Http400, "Unable to dial peer")
except CatchableError: except CatchableError:
return RestApiResponse.error(Http400, "Unknown error dialling peer") return RestApiResponse.error(Http500, "Unknown error dialling peer")
return router return router