Skip to main content
Glama
storage.ts2.8 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { Storage } from '@google-cloud/storage'; import { isString } from '@medplum/core'; import type { Binary } from '@medplum/fhirtypes'; import type { Readable } from 'node:stream'; import { BaseBinaryStorage } from '../../storage/base'; import type { BinarySource } from '../../storage/types'; export class GoogleCloudStorage extends BaseBinaryStorage { private readonly storage: Storage; private readonly bucket; constructor(bucketName: string) { super(); this.storage = new Storage(); this.bucket = this.storage.bucket(bucketName); } /** * Writes a file to Google Cloud Storage. * This method now correctly handles both Readable streams and strings as input. * @param key - The key (path) for the file in the bucket. * @param contentType - The MIME type of the content. * @param data - The content to write, either as a Readable stream or a string. */ async writeFile(key: string, contentType: string | undefined, data: BinarySource): Promise<void> { const file = this.bucket.file(key); const options = { metadata: { contentType: contentType ?? 'application/octet-stream' }, // Resumable uploads are generally recommended for robustness, especially for streams. // You can set this to false if you are certain you will only upload small files. resumable: true, }; if (isString(data)) { // For strings, the file.save() method is the most direct and simplest way. // It handles encoding and buffering automatically. await file.save(data, options); } else { // For streams, we pipe the data to a write stream provided by the client library. // We wrap this callback-based stream logic in a Promise to work seamlessly with async/await. await new Promise<void>((resolve, reject) => { const writeStream = file.createWriteStream(options); data .pipe(writeStream) .on('finish', () => resolve()) .on('error', (err) => reject(err)); }); } } async readFile(key: string): Promise<Readable> { const file = this.bucket.file(key); return file.createReadStream(); } async copyFile(sourceKey: string, destinationKey: string): Promise<void> { const sourceFile = this.bucket.file(sourceKey); const destinationFile = this.bucket.file(destinationKey); await sourceFile.copy(destinationFile); } async getPresignedUrl(binary: Binary): Promise<string> { const file = this.bucket.file(this.getKey(binary)); const options = { action: 'read' as const, expires: Date.now() + 3600 * 1000, }; const [url] = await file.getSignedUrl(options); return url; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server