mirror of https://github.com/kern/filepizza
Begin redis channel impl
parent
6a0ab981f0
commit
e70445530d
@ -1,23 +1,11 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
filepizza:
|
redis:
|
||||||
image: kern/filepizza:latest
|
image: redis:latest
|
||||||
restart: always
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
ports:
|
ports:
|
||||||
- 3333:3333
|
- 6379:6379
|
||||||
environment:
|
# coturn:
|
||||||
- PORT=3333
|
# image: instrumentisto/coturn:latest
|
||||||
- EXTRA_ICE_SERVERS=turn:localhost:3478
|
# network_mode: host
|
||||||
- WEBTORRENT_TRACKERS=ws://localhost:8000
|
# ports:
|
||||||
coturn:
|
# - 3478:3478
|
||||||
image: instrumentisto/coturn:latest
|
|
||||||
network_mode: host
|
|
||||||
ports:
|
|
||||||
- 3478:3478
|
|
||||||
bittorrent-tracker:
|
|
||||||
image: henkel/bittorrent-tracker:latest
|
|
||||||
command: ["npx", "bittorrent-tracker", "--http-hostname", "0.0.0.0", "--ws"]
|
|
||||||
ports:
|
|
||||||
- 8000:8000
|
|
||||||
|
|||||||
@ -0,0 +1,103 @@
|
|||||||
|
import config from './config'
|
||||||
|
import Redis from 'ioredis'
|
||||||
|
|
||||||
|
export type Channel = {
|
||||||
|
uploaderPeerID: string
|
||||||
|
longSlug: string
|
||||||
|
shortSlug: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ChannelRepo {
|
||||||
|
create(uploaderPeerID: string, ttl?: number): Promise<Channel>
|
||||||
|
fetch(slug: string): Promise<Channel | null>
|
||||||
|
renew(slug: string, ttl: number): Promise<void>
|
||||||
|
destroy(slug: string): Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RedisChannelRepo implements ChannelRepo {
|
||||||
|
client: Redis.Redis
|
||||||
|
|
||||||
|
constructor(redisURL: string) {
|
||||||
|
this.client = new Redis(redisURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(
|
||||||
|
uploaderPeerID: string,
|
||||||
|
ttl: number = config.channel.ttl,
|
||||||
|
): Promise<Channel> {
|
||||||
|
const shortSlug = await this.generateShortSlug()
|
||||||
|
const longSlug = await this.generateLongSlug()
|
||||||
|
|
||||||
|
const channel: Channel = {
|
||||||
|
uploaderPeerID,
|
||||||
|
longSlug,
|
||||||
|
shortSlug,
|
||||||
|
}
|
||||||
|
const channelStr = this.serializeChannel(channel)
|
||||||
|
|
||||||
|
await this.client.setex(this.getLongSlugKey(longSlug), ttl, channelStr)
|
||||||
|
await this.client.setex(this.getShortSlugKey(shortSlug), ttl, channelStr)
|
||||||
|
|
||||||
|
return channel
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetch(slug: string): Promise<Channel | null> {
|
||||||
|
const shortChannelStr = await this.client.get(this.getShortSlugKey(slug))
|
||||||
|
if (shortChannelStr) {
|
||||||
|
return this.deserializeChannel(shortChannelStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
const longChannelStr = await this.client.get(this.getLongSlugKey(slug))
|
||||||
|
if (longChannelStr) {
|
||||||
|
return this.deserializeChannel(longChannelStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
async renew(slug: string, ttl: number = config.channel.ttl): Promise<void> {
|
||||||
|
const channel = await this.fetch(slug)
|
||||||
|
if (!channel) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.client.expire(this.getShortSlugKey(channel.shortSlug), ttl)
|
||||||
|
await this.client.expire(this.getLongSlugKey(channel.longSlug), ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
async destroy(slug: string): Promise<void> {
|
||||||
|
const channel = await this.fetch(slug)
|
||||||
|
if (!channel) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.client.del(channel.longSlug)
|
||||||
|
await this.client.del(channel.shortSlug)
|
||||||
|
}
|
||||||
|
|
||||||
|
private async generateShortSlug(): Promise<string> {
|
||||||
|
return 'foo' // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private async generateLongSlug(): Promise<string> {
|
||||||
|
return 'foo/bar/baz' // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private getShortSlugKey(shortSlug: string): string {
|
||||||
|
return `short:${shortSlug}`
|
||||||
|
}
|
||||||
|
|
||||||
|
private getLongSlugKey(longSlug: string): string {
|
||||||
|
return `long:${longSlug}`
|
||||||
|
}
|
||||||
|
|
||||||
|
private serializeChannel(channel: Channel): string {
|
||||||
|
return JSON.stringify(channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
private deserializeChannel(str: string): Channel {
|
||||||
|
return JSON.parse(str) as Channel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const channelRepo = new RedisChannelRepo(config.redisURL)
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
redisURL: 'redis://localhost:6379/0',
|
||||||
|
channel: {
|
||||||
|
ttl: 60 * 60, // 1 hour
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
import type { Request, Response } from 'express'
|
||||||
|
import { channelRepo } from '../../channel'
|
||||||
|
|
||||||
|
export default (req: Request, res: Response): void => {
|
||||||
|
// TODO: validate method and uploaderPeerID
|
||||||
|
|
||||||
|
channelRepo
|
||||||
|
.create(req.body.uploaderPeerID)
|
||||||
|
.then((channel) => {
|
||||||
|
res.statusCode = 200
|
||||||
|
res.setHeader('Content-Type', 'application/json')
|
||||||
|
res.end(JSON.stringify(channel))
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
res.statusCode = 500
|
||||||
|
res.setHeader('Content-Type', 'application/json')
|
||||||
|
res.end(JSON.stringify({ error: err.toString() }))
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
import type { Request, Response } from 'express'
|
||||||
|
import { channelRepo } from '../../channel'
|
||||||
|
|
||||||
|
export default (req: Request, res: Response): void => {
|
||||||
|
// TODO: validate method and slug
|
||||||
|
|
||||||
|
channelRepo
|
||||||
|
.destroy(req.body.slug)
|
||||||
|
.then((channel) => {
|
||||||
|
res.statusCode = 200
|
||||||
|
res.setHeader('Content-Type', 'application/json')
|
||||||
|
res.end(JSON.stringify(channel))
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
res.statusCode = 500
|
||||||
|
res.setHeader('Content-Type', 'application/json')
|
||||||
|
res.end(JSON.stringify({ error: err.toString() }))
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
import type { Request, Response } from 'express'
|
||||||
|
import { channelRepo } from '../../channel'
|
||||||
|
|
||||||
|
export default (req: Request, res: Response): void => {
|
||||||
|
// TODO: validate method and slug
|
||||||
|
|
||||||
|
channelRepo
|
||||||
|
.renew(req.body.slug)
|
||||||
|
.then((channel) => {
|
||||||
|
res.statusCode = 200
|
||||||
|
res.setHeader('Content-Type', 'application/json')
|
||||||
|
res.end(JSON.stringify(channel))
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
res.statusCode = 500
|
||||||
|
res.setHeader('Content-Type', 'application/json')
|
||||||
|
res.end(JSON.stringify({ error: err.toString() }))
|
||||||
|
})
|
||||||
|
}
|
||||||
@ -1,26 +0,0 @@
|
|||||||
const { createServer } = require('http')
|
|
||||||
const { parse } = require('url')
|
|
||||||
const next = require('next')
|
|
||||||
const PeerDataServer = require('peer-data-server')
|
|
||||||
|
|
||||||
const appendPeerDataServer = PeerDataServer.default || PeerDataServer
|
|
||||||
const dev = process.env.NODE_ENV !== 'production'
|
|
||||||
const app = next({ dev })
|
|
||||||
const handle = app.getRequestHandler()
|
|
||||||
|
|
||||||
app.prepare().then(() => {
|
|
||||||
const server = createServer((req, res) => {
|
|
||||||
const parsedUrl = parse(req.url, true)
|
|
||||||
handle(req, res, parsedUrl)
|
|
||||||
})
|
|
||||||
|
|
||||||
appendPeerDataServer(server)
|
|
||||||
|
|
||||||
server.listen(3000, (err) => {
|
|
||||||
if (err) {
|
|
||||||
throw err
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('> Ready on http://localhost:3000')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
Loading…
Reference in New Issue