Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into emoji
Browse files Browse the repository at this point in the history
* 'develop' of github.com:RocketChat/Rocket.Chat:
  Chore: Bump fuselage (#25371)
  Chore: Add options to debug stdout and rate limiter (#25336)
  Regression: Fix English i18n react text (#25368)
  Regression: Rocket.Chat Webapp not loading. (#25349)
  Regression: Fix multi line is not showing an empty line between lines (#25317)
  Regression: bump onboarding-ui version (#25320)
  Chore: Create README.md for Rest Typings (#25335)
  Regression: Parser message when notify ephemeral message
  • Loading branch information
gabriellsh committed May 2, 2022
2 parents ae1fd33 + 2db109b commit 87ec3bd
Show file tree
Hide file tree
Showing 13 changed files with 272 additions and 142 deletions.
22 changes: 19 additions & 3 deletions apps/meteor/app/lib/server/startup/rateLimiter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,22 @@ import { DDPRateLimiter } from 'meteor/ddp-rate-limiter';
import { RateLimiter } from 'meteor/rate-limit';

import { settings } from '../../../settings/server';
import { metrics } from '../../../metrics';
import { Logger } from '../../../logger';
import { metrics } from '../../../metrics/server';
import { Logger } from '../../../logger/server';

const logger = new Logger('RateLimiter');

const slowDownRate = parseInt(process.env.RATE_LIMITER_SLOWDOWN_RATE);

const rateLimiterConsoleLog = ({ msg, reply, input }) => {
console.warn('DDP RATE LIMIT:', msg);
console.warn(JSON.stringify({ reply, input }, null, 2));
};

const rateLimiterLogger = ({ msg, reply, input }) => logger.info({ msg, reply, input });

const rateLimiterLog = String(process.env.RATE_LIMITER_LOGGER) === 'console' ? rateLimiterConsoleLog : rateLimiterLogger;

// Get initial set of names already registered for rules
const names = new Set(
Object.values(DDPRateLimiter.printRules())
Expand Down Expand Up @@ -85,6 +96,7 @@ RateLimiter.prototype.check = function (input) {
callbackReply.timeToReset = ruleResult.timeToNextReset;
callbackReply.allowed = false;
callbackReply.numInvocationsLeft = 0;
callbackReply.numInvocationsExceeded = numInvocations - rule.options.numRequestsAllowed;
rule._executeCallback(callbackReply, input);
// ==== END OVERRIDE ====
} else {
Expand Down Expand Up @@ -112,7 +124,7 @@ const ruleIds = {};

const callback = (msg, name) => (reply, input) => {
if (reply.allowed === false) {
logger.info({ msg, reply, input });
rateLimiterLog({ msg, reply, input });
metrics.ddpRateLimitExceeded.inc({
limit_name: name,
user_id: input.userId,
Expand All @@ -121,6 +133,10 @@ const callback = (msg, name) => (reply, input) => {
name: input.name,
connection_id: input.connectionId,
});
// sleep before sending the error to slow down next requests
if (slowDownRate > 0 && reply.numInvocationsExceeded) {
Meteor._sleepForMs(slowDownRate * reply.numInvocationsExceeded);
}
// } else {
// console.log('DDP RATE LIMIT:', message);
// console.log(JSON.stringify({ ...reply, ...input }, null, 2));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ const PlainText: FC<PlainTextType> = ({ value: text }) => {
const highlights = useMessageListHighlights();
const katex = useMessageListKatex();

// TODO ENG DAY:
// Add style for empty paragraphs in fuselage
if (!text.trim()) {
return <br />;
}

if (highlights || katex) {
return <CustomText text={text} wordsToHighlight={highlights} katex={katex} />;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ type TranslationRepliesKey =

// "You": "You",
// "You_user_have_reacted": "You have reacted",
// "Users_and_more_reacted_with": "__users__ and __count__ more have react with __emoji__",
// "You_and_more_Reacted_with": "You, __users__ and __count__ more have react with __emoji__",
// "You_and_Reacted_with": "You and __count__ more have react with __emoji__",
// "Users_and_more_reacted_with": "__users__ and __count__ more have reacted with __emoji__",
// "You_and_more_Reacted_with": "You, __users__ and __count__ more have reacted with __emoji__",
// "You_and_Reacted_with": "You and __count__ more have reacted with __emoji__",

const getTranslationKey = (users: string[], mine: boolean): TranslationRepliesKey => {
if (users.length === 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type SetupWizarContextValue = {

export const SetupWizardContext = createContext<SetupWizarContextValue>({
setupWizardData: {
adminData: { fullname: '', username: '', companyEmail: '', password: '' },
adminData: { fullname: '', username: '', email: '', password: '' },
organizationData: {
organizationName: '',
organizationType: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { useParameters } from '../hooks/useParameters';
import { useStepRouting } from '../hooks/useStepRouting';

const initialData: ContextType<typeof SetupWizardContext>['setupWizardData'] = {
adminData: { fullname: '', username: '', companyEmail: '', password: '' },
adminData: { fullname: '', username: '', email: '', password: '' },
organizationData: {
organizationName: '',
organizationType: '',
Expand Down Expand Up @@ -69,13 +69,13 @@ const SetupWizardProvider = ({ children }: { children: ReactElement }): ReactEle

const registerAdminUser = useCallback(async (): Promise<void> => {
const {
adminData: { fullname, username, companyEmail, password },
adminData: { fullname, username, email, password },
} = setupWizardData;
await registerUser({ name: fullname, username, email: companyEmail, pass: password });
await registerUser({ name: fullname, username, email, pass: password });
callbacks.run('userRegistered', {});

try {
await loginWithPassword(companyEmail, password);
await loginWithPassword(email, password);
} catch (error) {
if (error instanceof Meteor.Error && error.error === 'error-invalid-email') {
dispatchToastMessage({ type: 'success', message: t('We_have_sent_registration_email') });
Expand All @@ -90,7 +90,7 @@ const SetupWizardProvider = ({ children }: { children: ReactElement }): ReactEle
setForceLogin(false);

await defineUsername(username);
await dispatchSettings([{ _id: 'Organization_Email', value: companyEmail }]);
await dispatchSettings([{ _id: 'Organization_Email', value: email }]);
callbacks.run('usernameSet', {});
}, [defineUsername, dispatchToastMessage, loginWithPassword, registerUser, setForceLogin, dispatchSettings, setupWizardData, t]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const RegisterServerStep = (): ReactElement => {
stepCount={maxSteps}
onSubmit={handleRegister}
currentStep={currentStep}
initialValues={{ email: adminData.companyEmail }}
initialValues={{ email: adminData.email }}
/>
);
};
Expand Down
30 changes: 15 additions & 15 deletions apps/meteor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -189,24 +189,24 @@
"@nivo/pie": "0.73.0",
"@rocket.chat/apps-engine": "^1.31.0",
"@rocket.chat/core-typings": "workspace:^",
"@rocket.chat/css-in-js": "~0.31.10",
"@rocket.chat/emitter": "~0.31.10",
"@rocket.chat/css-in-js": "~0.31.11",
"@rocket.chat/emitter": "~0.31.11",
"@rocket.chat/forked-matrix-appservice-bridge": "^4.0.1",
"@rocket.chat/forked-matrix-bot-sdk": "^0.6.0-beta.2",
"@rocket.chat/fuselage": "~0.31.10",
"@rocket.chat/fuselage-hooks": "~0.31.10",
"@rocket.chat/fuselage-polyfills": "~0.31.10",
"@rocket.chat/fuselage-tokens": "~0.31.10",
"@rocket.chat/fuselage-ui-kit": "~0.31.10",
"@rocket.chat/icons": "~0.31.10",
"@rocket.chat/logo": "~0.31.10",
"@rocket.chat/memo": "~0.31.10",
"@rocket.chat/message-parser": "~0.31.10",
"@rocket.chat/fuselage": "~0.31.11",
"@rocket.chat/fuselage-hooks": "~0.31.11",
"@rocket.chat/fuselage-polyfills": "~0.31.11",
"@rocket.chat/fuselage-tokens": "~0.31.11",
"@rocket.chat/fuselage-ui-kit": "~0.31.11",
"@rocket.chat/icons": "~0.31.11",
"@rocket.chat/logo": "~0.31.11",
"@rocket.chat/memo": "~0.31.11",
"@rocket.chat/message-parser": "~0.31.11",
"@rocket.chat/mp3-encoder": "^0.24.0",
"@rocket.chat/onboarding-ui": "~0.31.10",
"@rocket.chat/onboarding-ui": "~0.31.11",
"@rocket.chat/rest-typings": "workspace:^",
"@rocket.chat/string-helpers": "~0.31.10",
"@rocket.chat/ui-kit": "~0.31.10",
"@rocket.chat/string-helpers": "~0.31.11",
"@rocket.chat/ui-kit": "~0.31.11",
"@slack/client": "^4.12.0",
"@types/cookie": "^0.4.1",
"@types/lodash": "^4.14.177",
Expand Down Expand Up @@ -344,7 +344,7 @@
"underscore.string": "^3.3.6",
"universal-perf-hooks": "^1.0.1",
"url-polyfill": "^1.1.12",
"use-subscription": "^1.6.0",
"use-subscription": "~1.6.0",
"uuid": "^3.4.0",
"webdav": "^2.10.2",
"xml-crypto": "^2.1.3",
Expand Down
8 changes: 4 additions & 4 deletions apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -4882,10 +4882,10 @@
"Yesterday": "Yesterday",
"You": "You",
"You_have_reacted": "You have reacted",
"Users_reacted_with": "__users__ have react with __emoji__",
"Users_and_more_reacted_with": "__users__ and __count__ more have react with __emoji__",
"You_and_users_Reacted_with": "You and __users__ have react with __emoji__",
"You_users_and_more_Reacted_with": "You, __users__ and __count__ more have react with __emoji__",
"Users_reacted_with": "__users__ have reacted with __emoji__",
"Users_and_more_reacted_with": "__users__ and __count__ more have reacted with __emoji__",
"You_and_users_Reacted_with": "You and __users__ have reacted with __emoji__",
"You_users_and_more_Reacted_with": "You, __users__ and __count__ more have reacted with __emoji__",
"You_are_converting_team_to_channel": "You are converting this Team to a Channel.",
"you_are_in_preview_mode_of": "You are in preview mode of channel #<strong>__room_name__</strong>",
"you_are_in_preview_mode_of_incoming_livechat": "You are in preview mode of this chat",
Expand Down
4 changes: 3 additions & 1 deletion apps/meteor/server/lib/logger/logQueue.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import EventEmitter from 'events';

const { MOLECULER_LOG_LEVEL, STDOUT_VIEWER_DISABLED = 'false' } = process.env;

type LogQueue = {
id: string;
data: string;
Expand Down Expand Up @@ -56,6 +58,6 @@ function queueWrite(...args: any): boolean {
return true;
}

if (String(process.env.MOLECULER_LOG_LEVEL).toLowerCase() !== 'debug') {
if (String(MOLECULER_LOG_LEVEL).toLowerCase() !== 'debug' && STDOUT_VIEWER_DISABLED === 'false') {
process.stdout.write = queueWrite;
}
7 changes: 7 additions & 0 deletions apps/meteor/server/modules/listeners/listeners.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { UserStatus, isSettingColor } from '@rocket.chat/core-typings';
import { parser } from '@rocket.chat/message-parser';

import { IServiceClass } from '../../sdk/types/ServiceClass';
import { NotificationsModule } from '../notifications/notifications.module';
import { EnterpriseSettings } from '../../sdk/index';

const { DISABLE_MESSAGE_PARSER = 'false' } = process.env;

const STATUS_MAP: { [k: string]: number } = {
[UserStatus.OFFLINE]: 0,
[UserStatus.ONLINE]: 1,
Expand Down Expand Up @@ -32,6 +35,10 @@ export class ListenersModule {
});

service.onEvent('notify.ephemeralMessage', (uid, rid, message) => {
if (message.msg && DISABLE_MESSAGE_PARSER !== 'true') {
message.md = parser(message.msg);
}

notifications.notifyUserInThisInstance(uid, 'message', {
groupable: false,
...message,
Expand Down
22 changes: 18 additions & 4 deletions apps/meteor/server/stream/stdout.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { performance } from 'perf_hooks';

import { EJSON } from 'meteor/ejson';
import { Log } from 'meteor/logging';

import notifications from '../../app/notifications/server/lib/Notifications';
import { getQueuedLogs, logEntries } from '../lib/logger/logQueue';

const processString = function (string: string, date: Date): string {
function processString(string: string, date: Date): string {
let obj;
try {
if (string[0] === '{') {
Expand All @@ -20,15 +22,27 @@ const processString = function (string: string, date: Date): string {
} catch (error) {
return string;
}
};
}

const transformLog = function (item: any): { id: string; string: string; ts: Date } {
function rawTransformLog(item: any): { id: string; string: string; ts: Date; time?: number } {
return {
id: item.id,
string: processString(item.data, item.ts),
ts: item.ts,
};
};
}

function timedTransformLog(log: any): { id: string; string: string; ts: Date; time?: number } {
const timeStart = performance.now();
const item = rawTransformLog(log);
const timeEnd = performance.now();

item.time = timeEnd - timeStart;

return item;
}

const transformLog = process.env.STDOUT_METRICS === 'true' ? timedTransformLog : rawTransformLog;

logEntries.on('log', (item) => {
// TODO having this as 'emitWithoutBroadcast' will not sent this data to ddp-streamer, so this data
Expand Down
85 changes: 85 additions & 0 deletions packages/rest-typings/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@

# @rocket.chat/rest-typings

Package containing all Rocket.Chat rest endpoint definitions


## Contributing

Contributions are always welcome!
However we have some recommendations.
- Check if your implementation matches your definitions, a bad definition is worse than none.
- Use the generic types we created for paging.
- Create functions that assert properties (very useful for the backend)
- Do tests to ensure that your assertions are correct.
- Avoid incomplete and unknow typings

### Good examples of what not to do:

#### If you have an endpoint that accepts name or id, both are not optional, one of them is required

```typescript

type EndPointTestGetParams = { name?: string; id?: string; } // WRONG!

type EndPointTestGetParams = { name: string; } | { id: string; } // Better :)
````

#### If you have an endpoint that accepts name or id, both are not optional, one of them is required

```typescript
export const isEndPointTestGetParams = (props: any) is EndPointTestGetParams => 'name' in prop || 'id' in prop; // WRONG!
// .... Better
import Ajv from 'ajv';
const ajv = new Ajv();
const endPointTestGetParams = {
oneOf: [
{
type: 'object',
properties: {
name: {
type: 'string',
},
},
required: ['name'],
additionalProperties: false,
},
{
type: 'object',
properties: {
id: {
type: 'string',
},
},
required: ['id'],
additionalProperties: false,
},
],
};
export const isEndPointTestGetParams = ajv.compile<EndPointTestGetParams>(endPointTestGetParams);
```
## Optimizations

we use interfaces to register endpoints, so if you use a custom version, or miss an endpoint, you don't necessarily need to recompile the code, you can do it in your own code

```typescript
declare module '@rocket.chat/rest-typings' {
interface Endpoints {
'custom/endpoint': {
GET: (params: PaginatedRequest<{ query: string }>) => PaginatedResult<{
some: string[];
}>;
};
}
}
```

## License

MIT

Loading

0 comments on commit 87ec3bd

Please sign in to comment.