Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
25 changes: 4 additions & 21 deletions lib/core/users/MongoDBUsersRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ type DatabaseUser = {
};
totalUsedSpaceBytes: 0;
maxSpaceBytes: 0;
referralPartner: null;
subscriptionPlan: {
isSubscribed: boolean;
};
Expand Down Expand Up @@ -71,36 +70,20 @@ export class MongoDBUsersRepository implements UsersRepository {
}

async create(data: CreateUserData): Promise<BasicUser> {
const user = await new Promise(
(resolve: (newUser: BasicUser) => void, reject) => {
this.userModel.create(data, (err: Error, user: DatabaseUser) => {
if (err) {
reject(err);
} else {
resolve({
id: user.id,
maxSpaceBytes: user.maxSpaceBytes,
uuid: user.uuid,
});
}
});
}
);
const createdUser = await this.userModel.create(data);

// TODO: Change storage-models to insert only, avoiding updates.
await this.userModel.updateOne(
{
_id: user.id,
},
{ _id: createdUser.id },
{
maxSpaceBytes: data.maxSpaceBytes,
activated: data.activated,
}
);

user.maxSpaceBytes = data.maxSpaceBytes;
createdUser.maxSpaceBytes = data.maxSpaceBytes;

return user;
return createdUser;
}

async updateById(id: string, update: any): Promise<User | null> {
Expand Down
1 change: 0 additions & 1 deletion lib/core/users/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export interface User {
subscriptionPlan?: {
isSubscribed?: boolean;
};
referralPartner?: string | null;
preferences?: {
dnt: boolean;
};
Expand Down
11 changes: 3 additions & 8 deletions lib/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const express = require('express');
const crossorigin = require('cors');
const helmet = require('helmet');
const Config = require('./config');
const Storage = require('storj-service-storage-models');
const DatabaseConnection = require('./models/database');
const { querystring } = require('./server/middleware/query-string');
const { ErrorHandlerFactory: errorHandler } = require('./server/middleware/error-handler');

Expand Down Expand Up @@ -87,11 +87,7 @@ Engine.HEALTH_INTERVAL = 30000;
Engine.prototype.start = function (callback) {
log.info('starting the bridge engine');

this.storage = new Storage(
this._config.storage.mongoUrl,
this._config.storage.mongoOpts,
{ logger: log }
);
this.storage = DatabaseConnection.createFromConfig(this._config.storage, log);

const { QUEUE_USERNAME, QUEUE_PASSWORD, QUEUE_HOST } = this._config;

Expand Down Expand Up @@ -127,7 +123,7 @@ Engine.prototype.start = function (callback) {

this.mailer = new Mailer(this._config.mailer);
this.contracts = new storj.StorageManager(
new MongoDBStorageAdapter(this.storage),
new MongoDBStorageAdapter(this.storage.connection),
{ disableReaper: true }
);
this.redis = require('redis').createClient(this._config.redis);
Expand Down Expand Up @@ -257,7 +253,6 @@ Engine.prototype._configureApp = function () {
routers.forEach(bindRoute);
app.use(unexpectedErrorLogger);
app.use(errorHandler({ logger: log }));

app.use(json());

const profile = this._config.server.public || this._config.server;
Expand Down
117 changes: 117 additions & 0 deletions lib/models/bucket.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import crypto from "crypto";
import { Schema, Document, Connection, Types } from "mongoose";
import { validate as uuidValidate, version as uuidVersion } from "uuid";
const errors = require("storj-service-error-types");

interface IBucket extends Document {
storage: number;
transfer: number;
status: "Active" | "Inactive";
pubkeys: string[];
user: string;
userId: string;
name: string;
maxFrameSize: number;
created: Date;
publicPermissions: ("PUSH" | "PULL")[];
encryptionKey: string;
}

const BucketSchema = new Schema<IBucket>(
{
storage: { type: Number, default: 0 },
transfer: { type: Number, default: 0 },
status: {
type: String,
enum: ["Active", "Inactive"],
default: "Active",
},
pubkeys: [{ type: String, ref: "PublicKey" }],
user: { type: String, ref: "User" },
userId: {
type: String,
required: true,
validate: {
validator: (value: string) =>
uuidValidate(value) && uuidVersion(value) === 4,
message: "Invalid UUID",
},
ref: "User",
},
name: {
type: String,
default: () => "Bucket-" + crypto.randomBytes(3).toString("hex"),
},
maxFrameSize: { type: Number, default: -1 },
created: { type: Date, default: Date.now },
publicPermissions: {
type: [{ type: String, enum: ["PUSH", "PULL"] }],
default: [],
},
encryptionKey: { type: String, default: "" },
},
{
statics: {
async create(
user: { _id: string; uuid: string },
data: { pubkeys?: string[]; name?: string },
callback: (err: Error | null, bucket?: IBucket) => void,
) {
const Bucket = this;

const bucket = new Bucket({
status: "Active",
pubkeys: data.pubkeys,
user: user._id,
userId: user.uuid,
});

if (data.name) {
bucket.name = data.name;
}

try {
await bucket.save();

const savedBucket = await Bucket.findOne({
_id: bucket._id,
});
if (!savedBucket) {
return callback(
new errors.InternalError(
"Failed to load created bucket",
),
);
}

callback(null, savedBucket);
} catch (err: any) {
if (err.code === 11000) {
return callback(
new errors.ConflictError(
"Name already used by another bucket",
),
);
}
callback(new errors.InternalError(err.message));
}
},
},
},
);

BucketSchema.index({ user: 1 });
BucketSchema.index({ userId: 1 });
BucketSchema.index({ created: 1 });
BucketSchema.index({ user: 1, name: 1 }, { unique: true });

BucketSchema.set("toObject", {
transform: (doc: any, ret: Record<string, any>) => {
delete ret.__v;
delete ret._id;
ret.id = doc._id;
},
});

export = (connection: Connection) =>
connection.model<IBucket>("Bucket", BucketSchema);
117 changes: 117 additions & 0 deletions lib/models/database.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
'use strict';

const assert = require('assert');
const mongoose = require('mongoose');

/**
* MongoDB storage interface
* @constructor
* @param {String} mongoURI
* @param {Object} mongoOptions
* @param {Object} storageOptions
*/
function Database(mongoURI, mongoOptions, storageOptions) {
if (!(this instanceof Database)) {
return new Database(mongoURI, mongoOptions, storageOptions);
}

assert(typeof mongoOptions === 'object', 'Invalid mongo options supplied');

this._uri = mongoURI;
this._options = mongoOptions;
this._log = (storageOptions && storageOptions.logger) || {
info: console.log,
debug: console.log,
error: console.error,
warn: console.warn,
};

this._connect();
}

Database.externalModels = require('storj-service-storage-models').models;
Database.localModels = {
Bucket: require('./bucket'),
User: require('./user'),
};
Database.constants = require('../constants');

/**
* Connects to the database
*/
Database.prototype._connect = function () {
const opts = Object.assign({ ssl: false }, this._options);

if (opts.server) {
this._log.warn(
'Deprecated \'server\' option detected in database configuration. ' +
'This option was removed in MongoDB driver 4.x and will be ignored. ' +
'Please remove it from your configuration.'
);
delete opts.server;
}

this._log.info('opening database connection at %s', this._uri);

this.connection = mongoose.createConnection(this._uri, opts);

this.connection.on('error', (err) => {
this._log.error('database connection error: %s', err.message);
});

this.connection.on('disconnected', () => {
this._log.warn('disconnected from database');
});

this.connection.on('connected', () => {
this._log.info('connected to database');
});

this.models = this._createBoundModels();
};

/**
* Return a dictionary of models bound to this connection
*/
Database.prototype._createBoundModels = function () {
const bound = {};

const allModels = {
...Database.externalModels,
...Database.localModels,
};

for (const model in allModels) {
bound[model] = allModels[model](this.connection);
}

return bound;
};
Comment on lines +76 to +89
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The models initialize their connection in the external library so I copied the same file to this repository to initialize the connection for external and local models instead of using https://github.com/internxt/service-storage-models/blob/master/index.js


/**
* Returns a promise that resolves when the connection is ready
*/
Database.prototype.ready = function () {
return new Promise((resolve, reject) => {
if (this.connection.readyState === 1) {
return resolve();
}
this.connection.once('connected', resolve);
this.connection.once('error', reject);
});
};

/**
* Creates a Database instance from a config object
* @param {Object} storageConfig - { mongoUrl, mongoOpts }
* @param {Object} [logger]
*/
Database.createFromConfig = function (storageConfig, logger) {
return new Database(
storageConfig.mongoUrl,
storageConfig.mongoOpts,
logger ? { logger } : {}
);
};

module.exports = Database;
Loading
Loading