db structure abstraction; async collection; update/insert queries; model saving
This commit is contained in:
4
lib/src/http/Controller.ts
Normal file
4
lib/src/http/Controller.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
export default class Controller {
|
||||
|
||||
}
|
||||
69
lib/src/http/CookieJar.ts
Normal file
69
lib/src/http/CookieJar.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Injectable } from '../../../di/src/decorator/Injection.ts'
|
||||
import { getCookies, setCookie, delCookie, ServerRequest } from '../external/http.ts'
|
||||
import { InMemCache } from '../support/InMemCache.ts'
|
||||
import { HTTPRequest } from './type/HTTPRequest.ts'
|
||||
|
||||
export interface Cookie {
|
||||
key: string,
|
||||
original_value: string,
|
||||
value: any,
|
||||
}
|
||||
|
||||
export type MaybeCookie = Cookie | undefined
|
||||
|
||||
// TODO cookie options (http only, expires, &c.)
|
||||
@Injectable()
|
||||
export class CookieJar {
|
||||
protected _parsed: { [key: string]: string } = {}
|
||||
protected _cache = new InMemCache()
|
||||
|
||||
constructor(
|
||||
protected request: HTTPRequest,
|
||||
) {
|
||||
this._parsed = getCookies(this.request.to_native)
|
||||
}
|
||||
|
||||
public async get(key: string): Promise<MaybeCookie> {
|
||||
// Try the cache
|
||||
if ( await this._cache.has(key) )
|
||||
return this._cache.fetch(key)
|
||||
|
||||
// If the cache missed, try to parse it and load in cache
|
||||
if ( key in this._parsed ) {
|
||||
let value = this._parsed[key]
|
||||
try {
|
||||
value = JSON.parse(atob(this._parsed[key]))
|
||||
} catch(e) {}
|
||||
|
||||
const cookie = {
|
||||
key,
|
||||
value,
|
||||
original_value: this._parsed[key],
|
||||
}
|
||||
|
||||
await this._cache.put(key, cookie)
|
||||
return cookie
|
||||
}
|
||||
}
|
||||
|
||||
public async set(key: string, value: any): Promise<void> {
|
||||
const original_value = btoa(JSON.stringify(value))
|
||||
const cookie = {
|
||||
key,
|
||||
value,
|
||||
original_value,
|
||||
}
|
||||
|
||||
await this._cache.put(key, value)
|
||||
setCookie(this.request.response, { name: key, value: original_value })
|
||||
}
|
||||
|
||||
public async has(key: string): Promise<boolean> {
|
||||
return (await this._cache.has(key)) || key in this._parsed
|
||||
}
|
||||
|
||||
public async delete(key: string): Promise<void> {
|
||||
await this._cache.drop(key)
|
||||
delCookie(this.request.response, key)
|
||||
}
|
||||
}
|
||||
3
lib/src/http/Middleware.ts
Normal file
3
lib/src/http/Middleware.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export class Middleware {
|
||||
|
||||
}
|
||||
115
lib/src/http/Request.ts
Normal file
115
lib/src/http/Request.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import { ServerRequest } from '../external/http.ts'
|
||||
import { HTTPProtocol, HTTPRequest, RemoteHost } from './type/HTTPRequest.ts'
|
||||
import { Response } from './Response.ts'
|
||||
import { HTTPResponse } from './type/HTTPResponse.ts'
|
||||
import Utility from '../service/utility/Utility.ts'
|
||||
import { Injectable } from '../../../di/src/decorator/Injection.ts'
|
||||
|
||||
@Injectable()
|
||||
export class Request implements HTTPRequest {
|
||||
public readonly response: HTTPResponse
|
||||
private readonly _deno_req: ServerRequest
|
||||
private _body: any
|
||||
private _query: { [key: string]: any } = {}
|
||||
|
||||
public readonly url: string
|
||||
public readonly method: string
|
||||
public readonly protocol: HTTPProtocol
|
||||
public readonly connection: Deno.Conn
|
||||
public readonly secure: boolean = false
|
||||
|
||||
public get headers() {
|
||||
return this._deno_req.headers
|
||||
}
|
||||
|
||||
get to_native(): ServerRequest {
|
||||
return this._deno_req
|
||||
}
|
||||
|
||||
get cookies() {
|
||||
return this.response.cookies
|
||||
}
|
||||
|
||||
constructor(
|
||||
protected utility: Utility,
|
||||
from: ServerRequest
|
||||
) {
|
||||
this._deno_req = from
|
||||
this.url = this._deno_req.url
|
||||
this.method = this._deno_req.method.toLowerCase()
|
||||
this.protocol = {
|
||||
string: this._deno_req.proto,
|
||||
major: this._deno_req.protoMajor,
|
||||
minor: this._deno_req.protoMinor,
|
||||
}
|
||||
this.connection = this._deno_req.conn
|
||||
this.response = new Response(this)
|
||||
}
|
||||
|
||||
public async prepare() {
|
||||
this._body = await Deno.readAll(this._deno_req.body)
|
||||
|
||||
const url_params = new URLSearchParams(this.url.substr(1))
|
||||
const param_obj = Object.fromEntries(url_params)
|
||||
const params: any = {}
|
||||
for ( const key in param_obj ) {
|
||||
if ( !param_obj.hasOwnProperty(key) ) continue
|
||||
if ( param_obj[key] === '' ) params[key] = true
|
||||
else params[key] = this.utility.infer(param_obj[key])
|
||||
}
|
||||
|
||||
this._query = params
|
||||
}
|
||||
|
||||
respond(res: any) {
|
||||
return this._deno_req.respond(res)
|
||||
}
|
||||
|
||||
// public body: RequestBody = {}
|
||||
// public original_body: RequestBody = {}
|
||||
|
||||
get remote() {
|
||||
return this.connection.remoteAddr as RemoteHost
|
||||
}
|
||||
|
||||
get body() {
|
||||
return this._body
|
||||
}
|
||||
|
||||
get query() {
|
||||
return this._query
|
||||
}
|
||||
|
||||
get hostname() {
|
||||
return this.headers.get('host')?.split(':')[0]
|
||||
}
|
||||
|
||||
get path() {
|
||||
return this.url.split('?')[0]
|
||||
}
|
||||
|
||||
get xhr() {
|
||||
return this.headers.get('x-requested-with')?.toLowerCase() === 'xmlhttprequest'
|
||||
}
|
||||
|
||||
/*
|
||||
body
|
||||
fresh/stale - cache
|
||||
remote ips (proxy)
|
||||
params
|
||||
route?
|
||||
signedCookies
|
||||
*/
|
||||
|
||||
/*
|
||||
accepts content type
|
||||
accepts charsets
|
||||
accepts encodings
|
||||
accepts languages
|
||||
get header
|
||||
is content type
|
||||
get param with default value
|
||||
get input with default value
|
||||
range header parser
|
||||
*/
|
||||
}
|
||||
30
lib/src/http/Response.ts
Normal file
30
lib/src/http/Response.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { HTTPResponse } from './type/HTTPResponse.ts'
|
||||
import { HTTPRequest } from './type/HTTPRequest.ts'
|
||||
import { ServerRequest } from '../external/http.ts'
|
||||
import {CookieJar} from "./CookieJar.ts";
|
||||
|
||||
export class Response implements HTTPResponse {
|
||||
public status = 200
|
||||
public headers = new Headers()
|
||||
public body = ''
|
||||
public readonly cookies: CookieJar
|
||||
|
||||
private readonly _deno_req: ServerRequest
|
||||
private readonly _request: HTTPRequest
|
||||
|
||||
private _sent = false
|
||||
get sent() {
|
||||
return this._sent
|
||||
}
|
||||
|
||||
constructor(to: HTTPRequest) {
|
||||
this._deno_req = to.to_native
|
||||
this._request = to
|
||||
this.cookies = new CookieJar(to)
|
||||
}
|
||||
|
||||
send() {
|
||||
this._sent = true
|
||||
return this._deno_req.respond(this)
|
||||
}
|
||||
}
|
||||
6
lib/src/http/SecureRequest.ts
Normal file
6
lib/src/http/SecureRequest.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { HTTPRequest } from './type/HTTPRequest.ts'
|
||||
import { Request } from './Request.ts'
|
||||
|
||||
export default class SecureRequest extends Request implements HTTPRequest {
|
||||
public readonly secure: boolean = true
|
||||
}
|
||||
30
lib/src/http/type/HTTPRequest.ts
Normal file
30
lib/src/http/type/HTTPRequest.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { ServerRequest } from '../../external/http.ts'
|
||||
import {HTTPResponse} from "./HTTPResponse.ts";
|
||||
|
||||
export interface HTTPProtocol {
|
||||
string: string,
|
||||
major: number,
|
||||
minor: number,
|
||||
}
|
||||
|
||||
export interface RemoteHost {
|
||||
hostname: string,
|
||||
port: number,
|
||||
transport: string,
|
||||
}
|
||||
|
||||
export interface HTTPRequest {
|
||||
url: string
|
||||
method: string
|
||||
protocol: HTTPProtocol
|
||||
headers: Headers
|
||||
connection: Deno.Conn
|
||||
response: HTTPResponse
|
||||
to_native: ServerRequest
|
||||
|
||||
remote: RemoteHost
|
||||
body: any
|
||||
query: any
|
||||
hostname: string | undefined
|
||||
secure: boolean
|
||||
}
|
||||
12
lib/src/http/type/HTTPResponse.ts
Normal file
12
lib/src/http/type/HTTPResponse.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import {CookieJar} from '../CookieJar.ts'
|
||||
|
||||
export interface HTTPResponse {
|
||||
status: number
|
||||
headers: Headers
|
||||
body: Uint8Array | Deno.Reader | string
|
||||
trailers?: () => Promise<Headers> | Headers
|
||||
sent: boolean
|
||||
cookies: CookieJar,
|
||||
|
||||
send: () => void
|
||||
}
|
||||
Reference in New Issue
Block a user