mirror of
https://github.com/seejohnrun/haste-server.git
synced 2026-02-10 16:01:32 +00:00
Add tests and fix docker files
This commit is contained in:
+1
-1
@@ -125,7 +125,7 @@ class App {
|
||||
winston.info('loading static document', { name, path: documentPath })
|
||||
|
||||
if (data) {
|
||||
this.documentHandler?.store.set(
|
||||
this.documentHandler?.store?.set(
|
||||
name,
|
||||
data,
|
||||
cb => {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
const DEFAULT_KEY_LENGTH = 10
|
||||
|
||||
export default {
|
||||
DEFAULT_KEY_LENGTH,
|
||||
}
|
||||
Vendored
-13
@@ -23,24 +23,11 @@ declare module 'rethinkdbdash' {
|
||||
table(s: string): RethinkFunctions
|
||||
}
|
||||
|
||||
// function rethink<T>(obj: T[]): RethinkArray<T>
|
||||
function rethink<T>(obj: T): RethinkClient<T>
|
||||
|
||||
export = rethink
|
||||
}
|
||||
|
||||
// export {}
|
||||
|
||||
// declare module 'connect-ratelimit' {
|
||||
// export = connectRateLimit
|
||||
// }
|
||||
|
||||
// declare namespace Express {
|
||||
// export interface Request {
|
||||
// sturl?: string
|
||||
// }
|
||||
// }
|
||||
|
||||
declare module 'connect-ratelimit' {
|
||||
function connectRateLimit(
|
||||
as: RateLimits,
|
||||
|
||||
@@ -5,22 +5,21 @@ import type { Config } from '../../types/config'
|
||||
import type { Store } from '../../types/store'
|
||||
import type { KeyGenerator } from '../../types/key-generator'
|
||||
import type { Document } from '../../types/document'
|
||||
|
||||
const defaultKeyLength = 10
|
||||
import constants from '../../constants'
|
||||
|
||||
class DocumentHandler {
|
||||
keyLength: number
|
||||
|
||||
maxLength: number
|
||||
maxLength?: number
|
||||
|
||||
public store: Store
|
||||
public store?: Store
|
||||
|
||||
keyGenerator: KeyGenerator
|
||||
|
||||
config: Config
|
||||
config?: Config
|
||||
|
||||
constructor(options: Document) {
|
||||
this.keyLength = options.keyLength || defaultKeyLength
|
||||
this.keyLength = options.keyLength || constants.DEFAULT_KEY_LENGTH
|
||||
this.maxLength = options.maxLength // none by default
|
||||
this.store = options.store
|
||||
this.config = options.config
|
||||
@@ -29,9 +28,9 @@ class DocumentHandler {
|
||||
|
||||
public handleGet(request: Request, response: Response) {
|
||||
const key = request.params.id.split('.')[0]
|
||||
const skipExpire = !!this.config.documents[key]
|
||||
const skipExpire = !!this.config?.documents[key]
|
||||
|
||||
this.store.get(
|
||||
this.store?.get(
|
||||
key,
|
||||
ret => {
|
||||
if (ret) {
|
||||
@@ -75,7 +74,7 @@ class DocumentHandler {
|
||||
}
|
||||
// And then save if we should
|
||||
this.chooseKey(key => {
|
||||
this.store.set(key, buffer, res => {
|
||||
this.store?.set(key, buffer, res => {
|
||||
if (res) {
|
||||
winston.verbose('added document', { key })
|
||||
response.writeHead(200, { 'content-type': 'application/json' })
|
||||
@@ -124,9 +123,9 @@ class DocumentHandler {
|
||||
|
||||
public handleRawGet(request: Request, response: Response) {
|
||||
const key = request.params.id.split('.')[0]
|
||||
const skipExpire = !!this.config.documents[key]
|
||||
const skipExpire = !!this.config?.documents[key]
|
||||
|
||||
this.store.get(
|
||||
this.store?.get(
|
||||
key,
|
||||
ret => {
|
||||
if (ret) {
|
||||
@@ -158,7 +157,7 @@ class DocumentHandler {
|
||||
|
||||
if (!key) return
|
||||
|
||||
this.store.get(
|
||||
this.store?.get(
|
||||
key,
|
||||
(ret: string | boolean) => {
|
||||
if (ret) {
|
||||
|
||||
@@ -2,21 +2,11 @@ import type { Config } from '../../types/config'
|
||||
import type { Store } from '../../types/store'
|
||||
|
||||
const build = async (config: Config): Promise<Store> => {
|
||||
const DocumentStore = (
|
||||
await import(`../document-stores/${config.storage.type}`)
|
||||
).default
|
||||
|
||||
if (process.env.REDISTOGO_URL && config.storage.type === 'redis') {
|
||||
// const redisClient = require("redis-url").connect(process.env.REDISTOGO_URL);
|
||||
// Store = require("./lib/document-stores/redis");
|
||||
// preferredStore = new Store(config.storage, redisClient);
|
||||
|
||||
const DocumentStore = (await import(`../document-stores/${config.storage.type}`)).default
|
||||
|
||||
return new DocumentStore(config.storage)
|
||||
}
|
||||
const DocumentStore = (await import(`../document-stores/${config.storage.type}`)).default
|
||||
|
||||
return new DocumentStore(config.storage)
|
||||
|
||||
return new DocumentStore(config.storage)
|
||||
}
|
||||
|
||||
export default build
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
import * as winston from 'winston'
|
||||
import { createClient } from 'redis'
|
||||
import { bool } from 'aws-sdk/clients/redshiftdata'
|
||||
import { Callback, Store } from '../../types/store'
|
||||
import { RedisStoreConfig } from '../../types/config'
|
||||
|
||||
export type RedisClientType = ReturnType<typeof createClient>
|
||||
|
||||
// For storing in redis
|
||||
// options[type] = redis
|
||||
// options[url] - the url to connect to redis
|
||||
// options[host] - The host to connect to (default localhost)
|
||||
// options[port] - The port to connect to (default 5379)
|
||||
// options[db] - The db to use (default 0)
|
||||
// options[expire] - The time to live for each key set (default never)
|
||||
|
||||
class RedisDocumentStore implements Store {
|
||||
type: string
|
||||
|
||||
expire?: number | undefined
|
||||
|
||||
client?: RedisClientType
|
||||
|
||||
constructor(options: RedisStoreConfig) {
|
||||
this.expire = options.expire
|
||||
this.type = options.type
|
||||
this.connect(options)
|
||||
}
|
||||
|
||||
connect = (options: RedisStoreConfig) => {
|
||||
winston.info('configuring redis')
|
||||
|
||||
const url = process.env.REDISTOGO_URL || options.url
|
||||
const host = options.host || '127.0.0.1'
|
||||
const port = options.port || 6379
|
||||
const index = options.db || 0
|
||||
|
||||
if (url) {
|
||||
this.client = createClient({ url })
|
||||
this.client.connect()
|
||||
} else {
|
||||
this.client = createClient({
|
||||
url: `http://${host}:${port}`,
|
||||
database: index as number,
|
||||
username: options.username,
|
||||
password: options.password,
|
||||
})
|
||||
}
|
||||
|
||||
this.client.on('error', err => {
|
||||
winston.error('redis disconnected', err)
|
||||
})
|
||||
|
||||
this.client
|
||||
.select(index as number)
|
||||
.then(() => {
|
||||
winston.info(
|
||||
`connected to redis on ${url || `${host}:${port}`}/${index}`,
|
||||
)
|
||||
})
|
||||
.catch(err => {
|
||||
winston.error(`error connecting to redis index ${index}`, {
|
||||
error: err,
|
||||
})
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
getExpire = (skipExpire?: bool) => (!skipExpire ? { EX: this.expire } : {})
|
||||
|
||||
get = (key: string, callback: Callback): void => {
|
||||
this.client
|
||||
?.get(key)
|
||||
.then(reply => {
|
||||
callback(reply || false)
|
||||
})
|
||||
.catch(() => {
|
||||
callback(false)
|
||||
})
|
||||
}
|
||||
|
||||
set = (
|
||||
key: string,
|
||||
data: string,
|
||||
callback: Callback,
|
||||
skipExpire?: boolean | undefined,
|
||||
): void => {
|
||||
this.client?.set(key, data, this.getExpire(skipExpire))
|
||||
.then(() => {
|
||||
callback(true)
|
||||
})
|
||||
.catch(() => {
|
||||
callback(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default RedisDocumentStore
|
||||
@@ -1,9 +1,14 @@
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
import { Config } from '../../types/config'
|
||||
|
||||
const getConfig = (): Config => {
|
||||
const configPath = process.argv.length <= 2 ? 'config.json' : process.argv[2]
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'))
|
||||
const configPath =
|
||||
process.argv.length <= 2 ? 'project-config.js' : process.argv[2]
|
||||
const config = JSON.parse(
|
||||
fs.readFileSync(path.join('config', configPath), 'utf8'),
|
||||
)
|
||||
|
||||
config.port = (process.env.PORT || config.port || 7777) as number
|
||||
config.host = process.env.HOST || config.host || 'localhost'
|
||||
|
||||
@@ -7,7 +7,7 @@ class DictionaryGenerator implements KeyGenerator {
|
||||
|
||||
dictionary: string[]
|
||||
|
||||
constructor(options: KeyGeneratorConfig, readyCallback: () => void) {
|
||||
constructor(options: KeyGeneratorConfig, readyCallback?: () => void) {
|
||||
// Check options format
|
||||
if (!options) throw Error('No options passed to generator')
|
||||
if (!options.path) throw Error('No dictionary path specified in options')
|
||||
@@ -21,7 +21,7 @@ class DictionaryGenerator implements KeyGenerator {
|
||||
|
||||
this.dictionary = data.split(/[\n\r]+/)
|
||||
|
||||
if (readyCallback) readyCallback()
|
||||
readyCallback?.()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,16 @@ export interface RethinkDbStoreConfig extends BaseStoreConfig {
|
||||
password: string
|
||||
}
|
||||
|
||||
export interface RedisStoreConfig extends BaseStoreConfig {
|
||||
url?: string
|
||||
host?: string
|
||||
port?: string
|
||||
db?: string
|
||||
user?: string
|
||||
username?: string | undefined
|
||||
password?: string
|
||||
}
|
||||
|
||||
export type GoogleStoreConfig = BaseStoreConfig
|
||||
|
||||
export type StoreConfig =
|
||||
@@ -59,6 +69,9 @@ export type StoreConfig =
|
||||
| AmazonStoreConfig
|
||||
| FileStoreConfig
|
||||
| MongoStoreConfig
|
||||
| RedisStoreConfig
|
||||
| RethinkDbStoreConfig
|
||||
| PostgresStoreConfig
|
||||
|
||||
export interface KeyGeneratorConfig {
|
||||
type: string
|
||||
|
||||
@@ -3,10 +3,10 @@ import type { KeyGenerator } from './key-generator'
|
||||
import type { Store } from './store'
|
||||
|
||||
export type Document = {
|
||||
store: Store
|
||||
config: Config
|
||||
maxLength: number
|
||||
keyLength: number
|
||||
store?: Store
|
||||
config?: Config
|
||||
maxLength?: number
|
||||
keyLength?: number
|
||||
keyGenerator: KeyGenerator
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import DocumentHandler from '../lib/document-handler'
|
||||
|
||||
export type RequestParams = {
|
||||
documentHandler: DocumentHandler
|
||||
}
|
||||
Reference in New Issue
Block a user