import {Client as minioClient} from 'minio'
//import aws from 'aws-sdk'
import {PassThrough} from 'stream'
export let myMinioClient
export let s3
// ── Public bucket ─────────────────────────────────────────────────────────────
/** Bucket for publicly readable assets (app icons, etc.) */
export const PUBLIC_BUCKET = process.env.publicBucket ?? 'commtool-public';
/** Bucket for org data/manifest assets (PWA icons, manifests, etc.) */
export const DATA_BUCKET = process.env.bucket ?? process.env.bucket ?? 'kpe20';
/**
* Build the direct public URL for an object in the public bucket.
*
* Override with S3publicBaseUrl when migrating away from MinIO
* (e.g. CloudFront, S3 virtual-host, custom CDN).
* TODO (S3 migration): set S3publicBaseUrl in env instead of removing this helper.
*
* @param {string} key
* @returns {string}
*/
export const publicObjectUrl = (key) =>
`${process.env.S3publicBaseUrl ?? `https://${process.env.S3endPoint}:${process.env.S3port}`}/${PUBLIC_BUCKET}/${key}`;
/** Set an anonymous read policy on a bucket (MinIO / S3). */
const setPublicReadPolicy = (bucket) => {
const policy = JSON.stringify({
Version: '2012-10-17',
Statement: [{
Effect: 'Allow',
Principal: { AWS: ['*'] },
Action: ['s3:GetObject'],
Resource: [`arn:aws:s3:::${bucket}/*`],
}],
});
return new Promise((resolve, reject) => {
myMinioClient.setBucketPolicy(bucket, policy, (err) => {
if (err) reject(err); else resolve();
});
});
};
/**
* Ensure the public bucket exists and is publicly readable.
* TODO (S3 migration): replace with @aws-sdk/client-s3 CreateBucket + PutBucketPolicy.
*/
export const initPublicBucket = async () => {
return new Promise((resolve, reject) => {
if (!myMinioClient) { reject('minio client not initialized'); return; }
myMinioClient.bucketExists(PUBLIC_BUCKET, (err, exists) => {
if (err) { reject(err); return; }
const onExists = () => setPublicReadPolicy(PUBLIC_BUCKET).then(resolve).catch(reject);
if (!exists) {
myMinioClient.makeBucket(PUBLIC_BUCKET, (err) => {
if (err) { reject(err); return; }
console.log(`bucket ${PUBLIC_BUCKET} created`);
onExists();
});
} else {
console.log(`bucket ${PUBLIC_BUCKET} already exists`);
onExists();
}
});
});
};
const configLifeCycle=(bucket)=>
{
const lifecycleConfig={
Rule: [{
"ID": "7 days",
"Status": "Enabled",
"Filter": {
"Prefix":'public/7',
},
"Expiration": {
"Days": "7"
}
},
{
"ID": "30 days",
"Status": "Enabled",
"Filter": {
"Prefix":'public/30',
},
"Expiration": {
"Days": "30"
}
},
{
"ID": "100 days",
"Status": "Enabled",
"Filter": {
"Prefix":'public/100',
},
"Expiration": {
"Days": "100"
}
},
{
"ID": "365 days",
"Status": "Enabled",
"Filter": {
"Prefix":'public/365',
},
"Expiration": {
"Days": "365"
}
}
]
}
return new Promise((resolve, reject) => {
myMinioClient.setBucketLifecycle(bucket,lifecycleConfig, function (err) {
if (err) {
throw("minio life cycle config Success"+err)
}
else
{
resolve()
}
})
})
}
export const initBucket= async (bucket)=>
{
return new Promise((resolve, reject) =>
{
if(!myMinioClient)
{
console.error('minio client not initialized')
reject('minio client not initialized')
return
}
myMinioClient.bucketExists(bucket, function(err, exists)
{
if (err)
{
throw new Error(`Error checking if bucket exists: ${err.message}`);
}
if (!exists)
{
myMinioClient.makeBucket(bucket, function(err) {
if (err)
{
console.error('Error creating bucket',bucket,err)
}
else
{
console.log(`bucket ${bucket} created successfully`)
configLifeCycle(bucket).then(()=>resolve())
}
})
}
else
{
console.log(`bucket ${bucket} already exists`)
configLifeCycle(bucket).then(()=>resolve())
}
})
})
}
export const initS3= async () =>
{
try
{
myMinioClient = new minioClient({
endPoint: process.env.S3endPoint,
port: parseInt(process.env.S3port),
useSSL: process.env.S3useSSL==='true',
accessKey: process.env.S3accessKey,
secretKey: process.env.S3secretKey,
pathStyle: true,
region: process.env.S3region || 'us-east-1' // Default region if not specified
});
// Create S3-compatible wrapper around MinIO client for busboy compatibility
s3 = {
upload: (params, callback) => {
console.log('=== S3 UPLOAD DEBUG START ===');
const objectStream = params.Body instanceof PassThrough ? params.Body : new PassThrough();
// Stream-Events für Debugging
objectStream.on('data', (chunk) => {
console.log('Stream: received data chunk of', chunk.length, 'bytes');
});
objectStream.on('end', () => {
console.log('Stream: END event received');
});
objectStream.on('error', (err) => {
console.log('Stream: ERROR event:', err);
callback(err);
});
console.log('Calling myMinioClient.putObject...');
try {
myMinioClient.putObject(
params.Bucket,
params.Key,
objectStream, // ← Verwende den PassThrough-Stream
null,
params.Metadata || {},
(err, etag) => {
console.log('=== MINIO CALLBACK CALLED ===');
if (err) return callback(err);
callback(null, {
Location: `https://${process.env.S3endPoint}:${parseInt(process.env.S3port)}/${params.Bucket}/${params.Key}`,
key: params.Key,
Key: params.Key,
Bucket: params.Bucket,
ETag: etag
});
}
);
} catch (err) {
callback(err);
}
// Gib das S3-kompatible Interface zurück
return {
Body: objectStream // ← Das ist der Stream, in den geschrieben wird
};
}
};
await initBucket(process.env.bucket);
await initPublicBucket();
}
catch(e)
{
console.error('minio connection failed')
if(!process.env.S3endPoint)
console.error('you have to pass the environment variable "S3endPoint"')
if(!process.env.S3port)
console.error('you have to pass the environment variable "S3port"')
if(!process.env.S3accessKey)
console.error('you have to pass the environment variable "S3accessKey"')
if(!process.env.S3port)
console.error('you have to pass the environment variable "S3secretKey"')
console.error('your connection data may be invaliud or you forgot to pass S3useSSL=true for an ssl connection ')
}
}
/* original independant s3 client code, not used anymore, but kept for reference
try {
s3 = new aws.S3({
endpoint: `${process.env.S3endPoint}:${process.env.S3port}`,
accessKeyId: process.env.S3accessKey,
secretAccessKey: process.env.S3secretKey,
sslEnabled: process.env.S3useSSL==='true',
s3ForcePathStyle: true,
})
}
catch(e)
{
console.error('minio connection failed')
if(!process.env.S3endPoint)
console.error('you have to pass the environment variable "S3endPoint"')
if(!process.env.S3port)
console.error('you have to pass the environment variable "S3port"')
if(!process.env.S3accessKey)
console.error('you have to pass the environment variable "S3accessKey"')
if(!process.env.S3port)
console.error('you have to pass the environment variable "S3secretKey"')
console.error('your connection data may be invaliud or you frogot to pass S3useSSL=true for an ssl connection ')
}*/