-
Notifications
You must be signed in to change notification settings - Fork 202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@tus/s3-store: add object prefixing #457
Comments
Hi @Murderlon yes, a function would be better However, I think that the It can be called directly in the getFileIdFromRequest method In my use case, I'd need to access the new Server({
getObjectPrefix: (request:Request, upload: Upload) => {
return request.headers['tenant-id']
}
}) The only caveat here is that when we generate the URL on the As an example, we do exactly this in the Supabase storage-api overwrite the PostHandler getFileIdFromRequest and remove it on the |
I'm not sure that would be better. We already have If it's valuable to have the cc @Acconut |
Yea, I agree that doing it this way seems a bit hacky, somewhat seems like a workaround on the TUS protocol which maps URI 1:1 to the file path I believe that the use case is quite legitimate to have implicit paths, and it can apply to any sort of Storage adapter. In our case, we also support the FileStore adapter which we would need the same object prefixing functionality in there, hence I thought that having it at the server level could make sense since you want this prefix shared across all store adapters. I agree that const server = new Server({
generateUrl(): string {
....
},
getFileIdFromRequest(): string {
...
}
}) This way the user can have the freedom of customising the URL to its liking and still be consistent to the underline TUS protocol |
I agree that it would be useful to be able to separate the upload ID (and thus the upload URL) from the storage path. Sometimes you want to customize the upload URL, sometimes the storage path, and sometimes both. It's not the most pressing issue, so the first approach for implementation was to just couple the two together. We could thing about a general solution where the user is able to fully influence the storage path for all storages, but I think adding an option for object prefix is also fine. That's the easier option for users if they don't want to fiddle around with a custom storage path generation approach.
It's worth noting that the tus protocol itself does not make any assumption about the URL format or the storage path. They can be whatever they want. Only in our implementation (tusd and tus-node-server) we have added the concept of an upload ID that corresponds to the destination because it is a simple implementation that works great in most situations. |
I like the idea of splitting it into two functions. However it puts quite the burden on on the implementer and would make tus-node-server/packages/server/src/handlers/BaseHandler.ts Lines 35 to 70 in 0af377d
Those are complexities I'd rather keep internal. If the problem is specifically about augmenting storage paths, then think we should keep solution tied to the storage solutions rather than make the ID's "magical". We can do something like this: const {Server} = require('@tus/server')
const {FileStore} = require('@tus/file-store')
const {S3Store} = require('@tus/s3-store')
const getFilePath = (req, upload) => req.headers['tenant-id']
const s3Store = new S3Store({getFilePath})
const fileStore = new FileStore({getFilePath})
const datastore = useFileStore ? fileStore : s3Store
const server = new Server({path: '/files', datastore}) |
Alternatively, you could also generate the storage path once before upload is created and then store it in the upload's info object persistently. Whenever, you load an upload, you first look up the info file, extract the storage path and then load the upload from there. The benefit is that you do not have to derive the storage path from the upload ID for every request. The downside is that this way the info file cannot have a custom path. |
To toss another variant in here: We'd like to store the metadata in a different location/prefix than the resulting file. |
@Murderlon @fenos Would you mind giving an example of how to use these functions to set an object prefix in S3? With @tus/[email protected] and @tus/[email protected] I was able to set an object prefix using the I tried moving my prefix logic from To be honest I'm feeling a little bit confused about the overlap between Any ideas? Thanks in advance, and thanks for your work on this. Tus is a life saver. |
Hi, thanks for the feedback. There definitely should not have been a regression so I'll take a look. I'll see what I can do about the docs as well to clear it up and perhaps we want to think about deprecating |
@elliotdickison do you have a reproducible example? I created a test and ran it against the latest version and on it.only('should use namingFunction correctly', (done) => {
const server = new Server({
path: '/test/output',
datastore: new FileStore({directory: './test/output'}),
namingFunction() {
return '1234/5678'
},
})
const length = Buffer.byteLength('test', 'utf8').toString()
request(server.listen())
.post(server.options.path)
.set('Tus-Resumable', TUS_RESUMABLE)
.set('Upload-Length', length)
.then((res) => {
console.log(res.headers.location)
request(server.listen())
.patch(removeProtocol(res.headers.location))
.send('test')
.set('Tus-Resumable', TUS_RESUMABLE)
.set('Upload-Offset', '0')
.set('Content-Type', 'application/offset+octet-stream')
.expect(204, done)
})
}) |
Thanks for the quick response and updated docs, those did help. Now that I understand the functions I've pinpointed the problem I'm having: I used to be able to do this:
Based on your updated documentation I tried the following, but it doesn't behave as I would hope:
As far as I can tell it is now impossible to include a |
As fas as I can tell, tus-node-server/packages/file-store/index.ts Lines 60 to 62 in da1f740
So we would probably have to consistently add and test it in all stores. |
Ah ok, thanks for the clarification. I think that, in terms of object storage at least, being able to include slashes in the name is pretty tablestakes. I'd be up for contributing a PR if you can think of a good API. I can think of two options:
|
Now that I'm reading the description of this PR again though ("Prefixing can be used to create a pseudo-directory structure in the bucket."), what is the PR about if not allowing slashes in the object key? Am I misunderstanding the discussion here? |
@elliotdickison @Murderlon the 2 functions introduced allowed me to do exactly this, adding a prefix and storing files under a subfolder. The way i'm doing it is the following, i use the function namingFunction() {
return `my/sub/folder/id`
}
function generateUrl(_, { proto, host, baseUrl, path, id }) {
id = Buffer.from(id, 'utf-8').toString('base64url')
return `${proto}://${host}${path}/${id}`
}
function getFileIdFromRequest(req) {
const match = reExtractFileID.exec(req.url as string)
if (!match || tusPath.includes(match[1])) {
return
}
const idMatch = Buffer.from(match[1], 'base64url').toString('utf-8')
return idMatch
} This seems to work as intended. However, for the FileStore it's true that is not supported out of the box, so I simply extended the default store and overwritten the |
@fenos That did the trick! Thank you very much. |
I'll take a look next week at supporting this in file store too and updating the docs to include the above example. |
Added in this PR now: #549 |
This is important to note, read example-store-files-in-custom-nested-directories and setup accordingly. I leave this here for others to find. To prevent running into errors such as: p.s. While we're at it, using nginx you will also need to add a proxy_redirect |
Thank you all and @lalilaloe thank you so much for adding this nugget of information to get custom file paths! So much appreciated! Would be amazing if |
Thanks to tus/tusd#1083, the latest release candidate of tusd support fully customized paths for the file store. Soon (see tus/tusd#1167) the same will be possible for the S3 store, followed by Azure and Google Cloud Storage support :) |
Prefixing can be used to create a pseudo-directory structure in the bucket.
tusd supports this with a hardcoded
ObjectPrefix
option:https://github.com/tus/tusd/blob/b4ffdf43f034099ee46437271de2ff98c1f52397/pkg/s3store/s3store.go#L987-L994
in @tus/s3-store we have
partKey
where this could be supported:tus-node-server/packages/s3-store/index.ts
Lines 144 to 154 in 0af377d
However it might be more flexible have a function
getObjectPrefix (upload: Upload) => string
so it can be done dynamically based on metadata?cc @fenos
The text was updated successfully, but these errors were encountered: