Skip to content

Commit

Permalink
Use korpRequest in KwicProxy
Browse files Browse the repository at this point in the history
  • Loading branch information
arildm committed Dec 13, 2024
1 parent 8cdfd78 commit 8f6d27b
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 48 deletions.
9 changes: 8 additions & 1 deletion app/scripts/backend/base-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ export default abstract class BaseProxy<R extends {} = {}> {
progress: number
total: number | null
total_results: number | null
// TODO When Axios is used in all (abortable) subclasses, remove `pendingRequests`
pendingRequests: JQuery.jqXHR[]
abortControllers: AbortController[] = []

constructor() {
this.prev = ""
Expand Down Expand Up @@ -43,15 +45,20 @@ export default abstract class BaseProxy<R extends {} = {}> {

abort(): void {
this.pendingRequests.forEach((req) => req.abort())
this.abortControllers.forEach((controller) => controller.abort())
this.cleanup()
}

cleanup(): void {
this.abortControllers = []
this.prev = ""
}

hasPending(): boolean {
return _.some(_.map(this.pendingRequests, (req) => req.readyState !== 4 && req.readyState !== 0))
return (
_.some(_.map(this.pendingRequests, (req) => req.readyState !== 4 && req.readyState !== 0)) ||
this.abortControllers.length > 0
)
}

/** Try to parse partial JSON data (of an in-progress HTTP response). */
Expand Down
16 changes: 13 additions & 3 deletions app/scripts/backend/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,24 @@ import { axiosConfAddMethod } from "@/util"
import { getAuthorizationHeader } from "@/components/auth/auth"
import settings from "@/settings"
import { API, ErrorMessage, Response, ResponseBase } from "./types"
import axios from "axios"
import axios, { AxiosProgressEvent } from "axios"

type KorpRequestOptions = {
abortSignal?: AbortSignal
onProgress?: (event: AxiosProgressEvent) => void
}

export async function korpRequest<K extends keyof API>(
endpoint: K,
params: API[K]["params"]
params: API[K]["params"],
options?: KorpRequestOptions
): Promise<ResponseBase & API[K]["response"]> {
const conf = axiosConfAddMethod({
url: settings.korp_backend_url + "/" + endpoint,
url: korpEndpointUrl(endpoint),
params,
headers: getAuthorizationHeader(),
onDownloadProgress: options?.onProgress,
signal: options?.abortSignal,
})
const response = await axios.request<Response<API[K]["response"]>>(conf)
const data = response.data
Expand All @@ -25,6 +33,8 @@ export async function korpRequest<K extends keyof API>(
return data
}

export const korpEndpointUrl = (endpoint: keyof API): string => settings.korp_backend_url + "/" + endpoint

export class KorpBackendError extends Error {
constructor(public readonly message: string, public readonly details: string) {
super(message)
Expand Down
46 changes: 21 additions & 25 deletions app/scripts/backend/kwic-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
import _ from "lodash"
import settings from "@/settings"
import BaseProxy from "@/backend/base-proxy"
import { locationSearchGet, Factory, ajaxConfAddMethod } from "@/util"
import { locationSearchGet, Factory, buildUrl } from "@/util"
import { ProgressReport, Response } from "./types"
import { QueryParams, QueryResponse } from "./types/query"
import { AjaxSettings } from "@/jquery.types"
import { korpEndpointUrl, korpRequest } from "./common"

export class KwicProxy extends BaseProxy<QueryResponse> {
prevCQP?: string
Expand All @@ -19,12 +19,12 @@ export class KwicProxy extends BaseProxy<QueryResponse> {
this.prevParams = null
}

makeRequest(
async makeRequest(
options: KorpQueryRequestOptions,
page: number | undefined,
progressCallback: (data: ProgressReport<QueryResponse>) => void,
kwicCallback: (data: Response<QueryResponse>) => void
): JQuery.jqXHR<Response<QueryResponse>> {
): Promise<QueryResponse> {
const self = this
this.resetRequest()
if (!kwicCallback) {
Expand Down Expand Up @@ -90,38 +90,34 @@ export class KwicProxy extends BaseProxy<QueryResponse> {
}

this.prevParams = data
const ajaxSettings = {
url: settings.korp_backend_url + "/" + command,
data: data,
beforeSend(req, settings) {
self.addAuthorizationHeader(req)
self.prevUrl = settings.url
},
this.prevUrl = buildUrl(korpEndpointUrl("query"), data)

success(data: QueryResponse, status, jqxhr) {
self.queryData = data.query_data
self.cleanup()
// Run the callback to show results, if not already done by the progress handler
if (!this.foundKwic) kwicCallback(data)
},
const abortController = new AbortController()
this.abortControllers.push(abortController)
let foundKwic = false

progress(jqxhr, e: ProgressEvent) {
const request = korpRequest(command, data, {
abortSignal: abortController.signal,
onProgress(e) {
// Calculate progress, used for progress bars
const progressObj = self.calcProgress(e)
const progressObj = self.calcProgress(e.event!)
progressCallback(progressObj)

// Show current page of results if they are available
// The request may continue to count hits in the background
if ("kwic" in progressObj.struct) {
this.foundKwic = true
foundKwic = true
kwicCallback(progressObj.struct as QueryResponse)
}
},
} satisfies AjaxSettings

const def = $.ajax(ajaxConfAddMethod(ajaxSettings)) as JQuery.jqXHR<Response<QueryResponse>>
this.pendingRequests.push(def)
return def
})

const result = await request
self.queryData = result.query_data
self.cleanup()
// Run the callback to show results, if not already done by the progress handler
if (!foundKwic) kwicCallback(result)
return result
}
}

Expand Down
5 changes: 5 additions & 0 deletions app/scripts/backend/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,9 @@ export type API = {
params: QueryParams
response: QueryResponse
}
relations_sentences: {
// The params actually differ slightly, but they are merged in QueryParams
params: QueryParams
response: QueryResponse
}
}
1 change: 1 addition & 0 deletions app/scripts/components/results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ angular.module("korpApp").component("results", {
</uib-tab>
</uib-tabset>
<!-- TODO Url may be too long. Store endpoint+params instead, and then make a request using axiosConfAddMethod() instead of just <a href> -->
<a id="json-link" ng-href="{{$root.jsonUrl}}" ng-show="$root.jsonUrl" target="_blank">
<img src="img/json.png" />
</a>
Expand Down
4 changes: 2 additions & 2 deletions app/scripts/controllers/example_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type ExampleCtrlScope = ScopeBase & {
hitsPictureData?: any
hitspictureClick?: (page: number) => void
kwicTab: KwicTab
makeRequest: (isPaging?: boolean) => JQuery.jqXHR<Response<QueryResponse>>
makeRequest: (isPaging?: boolean) => Promise<QueryResponse>
onExampleProgress: (progressObj: ProgressReport, isPaging?: boolean) => void
setupReadingWatch: () => void
superRenderResult: (data: Response<QueryResponse>) => void
Expand Down Expand Up @@ -145,7 +145,7 @@ class ExampleCtrl extends KwicCtrl {
}
)

def.fail(() => {
def.catch(() => {
$timeout(() => {
// TODO it could be abort
s.error = true
Expand Down
28 changes: 12 additions & 16 deletions app/scripts/controllers/kwic_controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @format */
import angular, { IController, ITimeoutService } from "angular"
import _ from "lodash"
import { CanceledError } from "axios"
import settings from "@/settings"
import kwicProxyFactory, { type KwicProxy } from "@/backend/kwic-proxy"
import { ApiKwic, Response, ProgressReport } from "@/backend/types"
Expand Down Expand Up @@ -209,8 +210,9 @@ export class KwicCtrl implements IController {

s.loading = true
s.aborted = false

s.ignoreAbort = Boolean(s.proxy.hasPending())
// If this request aborts a previous request, flag to abort it silently
// TODO Aborting the new request should not also be silent
s.ignoreAbort = s.proxy.hasPending()

const ajaxParams = s.buildQueryOptions(isPaging)

Expand All @@ -220,27 +222,21 @@ export class KwicCtrl implements IController {
(progressObj) => $timeout(() => s.onProgress(progressObj, isPaging)),
(data) => $timeout(() => s.renderResult(data))
)
req.done((data: Response<QueryResponse>) => {

req.then((data: QueryResponse) => {
$timeout(() => {
s.loading = false
s.renderCompleteResult(data, isPaging)
})
})

req.fail((jqXHR, status, errorThrown) => {
$timeout(() => {
console.log("kwic fail")
if (s.ignoreAbort) {
console.log("stats ignoreabort")
return
}
req.catch((err) => {
// If next request is already started, do nothing for this previous one
if (s.ignoreAbort) return
s.$applyAsync(() => {
s.loading = false

if (status === "abort") {
s.aborted = true
} else {
s.error = true
}
if (err instanceof CanceledError) s.aborted = true
else s.error = true
})
})
}
Expand Down
2 changes: 1 addition & 1 deletion app/scripts/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ export function fetchConfAddMethod(url: string, params: Record<string, any>): {
return { url: buildUrl(url, params), request: {} }
}

export function axiosConfAddMethod(conf: AxiosRequestConfig & { url: string }): AxiosRequestConfig {
export function axiosConfAddMethod(conf: AxiosRequestConfig & { url: string }): AxiosRequestConfig & { url: string } {
// Like $http, Axios uses `data` for POST but `params` for GET.
conf.method = selectHttpMethod(conf.url, conf.params || {})
if (conf.method == "POST") {
Expand Down

0 comments on commit 8f6d27b

Please sign in to comment.