Skip to content

Commit

Permalink
feat: fetch specific feed index update (#629)
Browse files Browse the repository at this point in the history
  • Loading branch information
AuHau authored Apr 19, 2022
1 parent d3b75b1 commit a4672dc
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 14 deletions.
21 changes: 16 additions & 5 deletions src/feed/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { keccak256Hash } from '../utils/hash'
import { serializeBytes } from '../chunk/serialize'
import { Identifier, uploadSingleOwnerChunkData, makeSingleOwnerChunkFromData } from '../chunk/soc'
import { FeedUpdateOptions, fetchFeedUpdate } from '../modules/feed'
import { FeedUpdateOptions, fetchLatestFeedUpdate, FetchFeedUpdateResponse } from '../modules/feed'
import {
REFERENCE_HEX_LENGTH,
Reference,
Expand Down Expand Up @@ -38,6 +38,7 @@ export interface Epoch {
time: number
level: number
}

export type IndexBytes = Bytes<8>
export type Index = number | Epoch | IndexBytes | string

Expand Down Expand Up @@ -110,7 +111,7 @@ export async function findNextIndex(
options?: FeedUpdateOptions,
): Promise<HexString<typeof INDEX_HEX_LENGTH>> {
try {
const feedUpdate = await fetchFeedUpdate(ky, owner, topic, options)
const feedUpdate = await fetchLatestFeedUpdate(ky, owner, topic, options)

return makeHexString(feedUpdate.feedIndexNext, INDEX_HEX_LENGTH)
} catch (e) {
Expand Down Expand Up @@ -165,13 +166,23 @@ export async function downloadFeedUpdate(ky: Ky, owner: EthAddress, topic: Topic
}

export function makeFeedReader(ky: Ky, type: FeedType, topic: Topic, owner: HexEthAddress): FeedReader {
const download = async (options?: FeedUpdateOptions) => fetchFeedUpdate(ky, owner, topic, { ...options, type })

return {
type,
owner,
topic,
download,
async download(options?: FeedUpdateOptions): Promise<FetchFeedUpdateResponse> {
if (!options?.index) {
return fetchLatestFeedUpdate(ky, owner, topic, { ...options, type })
}

const update = await downloadFeedUpdate(ky, hexToBytes(owner), topic, options.index)

return {
reference: bytesToHex(update.reference),
feedIndex: options.index,
feedIndexNext: '',
}
},
}
}

Expand Down
16 changes: 15 additions & 1 deletion src/modules/feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,28 @@ export interface FeedUpdateOptions {
* Specifies the start date as unix time stamp
*/
at?: number

/**
* Can be 'epoch' or 'sequence' (default: 'sequence')
*/
type?: FeedType

/**
* Fetch specific previous Feed's update (default fetches latest update)
*/
index?: string
}

interface FeedUpdateHeaders {
/**
* The current feed's index
*/
feedIndex: string

/**
* The feed's index for next update.
* Only set for the latest update. If update is fetched using previous index, then this is an empty string.
*/
feedIndexNext: string
}
export interface FetchFeedUpdateResponse extends ReferenceResponse, FeedUpdateHeaders {}
Expand Down Expand Up @@ -86,7 +100,7 @@ function readFeedUpdateHeaders(headers: Headers): FeedUpdateHeaders {
* @param topic Topic in hex
* @param options Additional options, like index, at, type
*/
export async function fetchFeedUpdate(
export async function fetchLatestFeedUpdate(
ky: Ky,
owner: HexEthAddress,
topic: Topic,
Expand Down
73 changes: 70 additions & 3 deletions test/integration/bee-class.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Bee, BeeDebug, Collection, PssSubscription } from '../../src'
import { Bee, BeeDebug, BeeResponseError, Collection, PssSubscription } from '../../src'
import { makeSigner } from '../../src/chunk/signer'
import { makeSOCAddress, uploadSingleOwnerChunkData } from '../../src/chunk/soc'
import { ChunkReference } from '../../src/feed'
Expand Down Expand Up @@ -444,11 +444,12 @@ describe('Bee class', () => {
describe('feeds', () => {
const owner = testIdentity.address
const signer = testIdentity.privateKey
const topic = randomByteArray(32, Date.now())

it(
'feed writer with two updates',
'should write two updates',
async () => {
const topic = randomByteArray(32, Date.now())

const feed = bee.makeFeedWriter('sequence', topic, signer)
const referenceZero = makeBytes(32) // all zeroes

Expand All @@ -472,9 +473,75 @@ describe('Bee class', () => {
FEED_TIMEOUT,
)

it(
'should get specific feed update',
async () => {
const topic = randomByteArray(32, Date.now())

const feed = bee.makeFeedWriter('sequence', topic, signer)
const referenceZero = makeBytes(32) // all zeroes

await feed.upload(getPostageBatch(), referenceZero)

const firstLatestUpdate = await feed.download()
expect(firstLatestUpdate.reference).toEqual(bytesToHex(referenceZero))
expect(firstLatestUpdate.feedIndex).toEqual('0000000000000000')

const referenceOne = new Uint8Array([...new Uint8Array([1]), ...new Uint8Array(31)]) as ChunkReference
await feed.upload(getPostageBatch(), referenceOne)

const secondLatestUpdate = await feed.download()
expect(secondLatestUpdate.reference).toEqual(bytesToHex(referenceOne))
expect(secondLatestUpdate.feedIndex).toEqual('0000000000000001')

const referenceTwo = new Uint8Array([
...new Uint8Array([1]),
...new Uint8Array([1]),
...new Uint8Array(30),
]) as ChunkReference
await feed.upload(getPostageBatch(), referenceTwo)

const thirdLatestUpdate = await feed.download()
expect(thirdLatestUpdate.reference).toEqual(bytesToHex(referenceTwo))
expect(thirdLatestUpdate.feedIndex).toEqual('0000000000000002')

const sendBackFetchedUpdate = await feed.download({ index: '0000000000000001' })
expect(sendBackFetchedUpdate.reference).toEqual(bytesToHex(referenceOne))
expect(sendBackFetchedUpdate.feedIndex).toEqual('0000000000000001')
},
FEED_TIMEOUT,
)
it(
'should fail fetching non-existing index',
async () => {
const topic = randomByteArray(32, Date.now())

const feed = bee.makeFeedWriter('sequence', topic, signer)
const referenceZero = makeBytes(32) // all zeroes
await feed.upload(getPostageBatch(), referenceZero)

const firstLatestUpdate = await feed.download()
expect(firstLatestUpdate.reference).toEqual(bytesToHex(referenceZero))
expect(firstLatestUpdate.feedIndex).toEqual('0000000000000000')

try {
await feed.download({ index: '0000000000000001' })
throw new Error('Should fail')
} catch (err) {
const e = err as BeeResponseError

expect(e.status).toEqual(404)
expect(e.responseBody).toContain('chunk not found')
}
},
FEED_TIMEOUT,
)

it(
'create feeds manifest and retrieve the data',
async () => {
const topic = randomByteArray(32, Date.now())

const directoryStructure: Collection<Uint8Array> = [
{
path: 'index.html',
Expand Down
4 changes: 2 additions & 2 deletions test/integration/feed/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fetchFeedUpdate } from '../../../src/modules/feed'
import { fetchLatestFeedUpdate } from '../../../src/modules/feed'
import { hexToBytes, makeHexString } from '../../../src/utils/hex'
import { beeKy, ERR_TIMEOUT, getPostageBatch, testIdentity } from '../../utils'
import { ChunkReference, downloadFeedUpdate, findNextIndex, Index, uploadFeedUpdate } from '../../../src/feed'
Expand Down Expand Up @@ -56,7 +56,7 @@ describe('feed', () => {
const uploadedChunk = await uploadChunk(BEE_KY, 0)
await tryUploadFeedUpdate(BEE_KY, signer, topic, 0, uploadedChunk)

const feedUpdate = await fetchFeedUpdate(BEE_KY, owner, topic)
const feedUpdate = await fetchLatestFeedUpdate(BEE_KY, owner, topic)

expect(feedUpdate.feedIndex).toEqual('0000000000000000')
expect(feedUpdate.feedIndexNext).toEqual('0000000000000001')
Expand Down
6 changes: 3 additions & 3 deletions test/integration/modules/feed.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createFeedManifest, fetchFeedUpdate } from '../../../src/modules/feed'
import { createFeedManifest, fetchLatestFeedUpdate } from '../../../src/modules/feed'
import { HexString, hexToBytes, makeHexString } from '../../../src/utils/hex'
import {
beeKy,
Expand Down Expand Up @@ -29,7 +29,7 @@ describe('modules/feed', () => {
'empty feed update',
async () => {
const emptyTopic = '1000000000000000000000000000000000000000000000000000000000000000' as Topic
const feedUpdate = fetchFeedUpdate(BEE_KY, owner, emptyTopic)
const feedUpdate = fetchLatestFeedUpdate(BEE_KY, owner, emptyTopic)

await expect(feedUpdate).rejects.toThrow('Not Found')
},
Expand All @@ -53,7 +53,7 @@ describe('modules/feed', () => {
const socResponse = await uploadSOC(BEE_KY, owner, identifier, signature, socData, getPostageBatch())
expect(socResponse).toBeType('string')

const feedUpdate = await fetchFeedUpdate(BEE_KY, owner, oneUpdateTopic)
const feedUpdate = await fetchLatestFeedUpdate(BEE_KY, owner, oneUpdateTopic)
expect(feedUpdate.reference).toBeType('string')
expect(feedUpdate.feedIndex).toEqual('0000000000000000')
expect(feedUpdate.feedIndexNext).toEqual('0000000000000001')
Expand Down

0 comments on commit a4672dc

Please sign in to comment.