Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,7 @@ store

*.key

# Don't commit our internal ansibles!
ansible/prod.yml
ansible/staging.yml
ansible/mauve.yml
32 changes: 32 additions & 0 deletions @types/bt-fetch.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
declare module 'bt-fetch' {
export type TorrentManagerOptions = Partial<{
folder: string
timeout: number
reloadInterval: number
}>

export interface Torrent {
infoHash: Buffer
publicKey: Buffer
}

export type TorrentPublishOpts = Partial<{
name: string
comment: string
createdBy: string
creationDate: string
}>

export interface KeyPair {
publicKey: string
secretKey: string
}

export class TorrentManager {
constructor (opts: TorrentManagerOptions)
stopSeedingPublicKey (publicKey: string): Promise<boolean>
republishPublicKey (publicKey: string, secretKey: string, opts: TorrentPublishOpts): Promise<Torrent>
createKeypair (petname?: string): KeyPair
destroy (): Promise<void>
}
}
2 changes: 1 addition & 1 deletion ansible/roles/distributed_press/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ distributed_press_host: "localhost"
distributed_press_ipfs_provider: "builtin"

distributed_press_git_repo: "https://github.com/hyphacoop/api.distributed.press.git"
distributed_press_git_branch: "v1.0.0"
distributed_press_git_branch: "v1.1.0"
distributed_press_source: "{{distributed_press_home}}/api.distributed.press"

distributed_press_domain: "example.com"
Expand Down
3 changes: 3 additions & 0 deletions api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ async function apiBuilder (cfg: APIConfig): Promise<FastifyTypebox> {
hyper: {
path: path.join(protocolStoragePath, 'hyper')
},
bittorrent: {
path: path.join(protocolStoragePath, 'bittorrent')
},
http: {
path: path.join(protocolStoragePath, 'http')
}
Expand Down
10 changes: 9 additions & 1 deletion api/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,19 @@ export const IPFSProtocolFields = GenericProtocol(Type.Object({
pubKey: Type.String(), // ipns://{publishKey}
dnslink: Type.String()
}))
export const BitTorrentProtocolFields = GenericProtocol(Type.Object({
gateway: Type.String(), // same as gateway in HyperProtocolFields
magnet: Type.String(), // Used by most torrent clients. Note: Will not update in regular clients
infoHash: Type.String(), // Immutable link, similar to ipfs public key
pubKey: Type.String(), // Link to public key for BEP-46, similar to IPNS
dnslink: Type.String()
}))

export const Protocols = Type.Object({
http: HTTPProtocolFields,
hyper: HyperProtocolFields,
ipfs: IPFSProtocolFields
ipfs: IPFSProtocolFields,
bittorrent: BitTorrentProtocolFields
})
export const ProtocolStatus = Type.Record(Type.KeyOf(Protocols), Type.Boolean())
export const Site = Type.Object({
Expand Down
10 changes: 10 additions & 0 deletions config/sites.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ export class SiteConfigStore extends Config<Static<typeof Site>> {
promises.push(promise)
}

if (site.protocols.bittorrent) {
const promise = this.protocols.bittorrent
.sync(siteId, filePath, undefined, ctx)
.then((protocolLinks) => {
site.links.bittorrent = protocolLinks
})

promises.push(promise)
}

await Promise.all(promises)
await this.db.put(siteId, site)
}
Expand Down
4 changes: 3 additions & 1 deletion dns/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ test('basic dns resolve', async t => {
protocols: {
http: false,
ipfs: true,
hyper: true
hyper: true,
bittorrent: true
},
public: true
})
Expand All @@ -42,6 +43,7 @@ test('basic dns resolve', async t => {
const response = await dnsClient.query(`_dnslink.${site.domain}`, 'TXT')
t.true(hasAnswer(response, 'ipns'), 'returned dns query has an ipns entry')
t.true(hasAnswer(response, 'hyper'), 'returned dns query has a hyper entry')
t.true(hasAnswer(response, 'bittorrent'), 'returned dns query has a bittorrent entry')
t.is(response.answers.filter(ans => ans.type !== DNS.Packet.TYPE.TXT).length, 0, 'should not include any non-TXT entries')
})

Expand Down
9 changes: 9 additions & 0 deletions dns/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ export async function initDnsServer (port: number, store: SiteConfigStore, logge
data: `dnslink=${links.hyper.dnslink}`
})
}
if (links.bittorrent !== undefined) {
response.answers.push({
name,
type: dns2.Packet.TYPE.TXT,
class: dns2.Packet.CLASS.IN,
ttl: 60,
data: `dnslink=${links.bittorrent.dnslink}`
})
}
send(response)
})
.catch((error) => {
Expand Down
20 changes: 19 additions & 1 deletion fixtures/mockProtocols.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import { Static, TSchema } from '@sinclair/typebox'
import { HTTPProtocolFields, HyperProtocolFields, IPFSProtocolFields } from '../api/schemas.js'
import { HTTPProtocolFields, HyperProtocolFields, IPFSProtocolFields, BitTorrentProtocolFields } from '../api/schemas.js'
import { ProtocolManager } from '../protocols/index.js'
import Protocol, { Ctx, SyncOptions } from '../protocols/interfaces.js'

export class MockProtocolManager implements ProtocolManager {
http: MockHTTPProtocol
ipfs: MockIPFSProtocol
hyper: MockHyperProtocol
bittorrent: MockBitTorrentProtocol

constructor () {
this.ipfs = new MockIPFSProtocol()
this.http = new MockHTTPProtocol()
this.hyper = new MockHyperProtocol()
this.bittorrent = new MockBitTorrentProtocol()
}

async load (): Promise<void> {
const promises = [
this.ipfs.load(),
this.hyper.load(),
this.bittorrent.load(),
this.http.load()
]
await Promise.all(promises)
Expand All @@ -27,6 +30,7 @@ export class MockProtocolManager implements ProtocolManager {
const promises = [
this.ipfs.unload(),
this.hyper.unload(),
this.bittorrent.unload(),
this.http.unload()
]
await Promise.all(promises)
Expand Down Expand Up @@ -81,3 +85,17 @@ class MockHyperProtocol extends BaseMockProtocol<typeof HyperProtocolFields> {
}
}
}

class MockBitTorrentProtocol extends BaseMockProtocol<typeof BitTorrentProtocolFields> {
async sync (_id: string, _folderPath: string, _options?: SyncOptions, _ctx?: Ctx): Promise<Static<typeof BitTorrentProtocolFields>> {
return {
enabled: true,
link: 'bittorrent://example-link',
gateway: 'https://example-bittorrent-gateway/example-link',
dnslink: '/bittorrent/example-raw',
infoHash: 'bittorrent://example-link-infohash',
pubKey: 'bittorrent://example-link-publickey',
magnet: 'magnet:?xt:urn:btih:example-link&xs=urn:btpk:example-link'
}
}
}
3 changes: 2 additions & 1 deletion fixtures/siteConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export const exampleSiteConfig: Static<typeof NewSite> = {
protocols: {
http: true,
ipfs: false,
hyper: false
hyper: false,
bittorrent: false
},
public: true
}
Loading