Skip to content

Commit

Permalink
Merge pull request #14 from devalexanderdaza/develop
Browse files Browse the repository at this point in the history
chore(auto-merge-action): merge automatically
  • Loading branch information
github-actions[bot] authored Sep 29, 2022
2 parents 83e4cb1 + 35c36fa commit 172c0ae
Show file tree
Hide file tree
Showing 16 changed files with 1,514 additions and 866 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,8 @@ build/

# .swc
.swc/

# Database
**/*.db
db/*.db
*.db
15 changes: 12 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,25 +78,33 @@
},
"dependencies": {
"@adiwajshing/baileys": "^4.4.0",
"@adiwajshing/keyed-db": "^0.2.4",
"@hapi/boom": "^10.0.0",
"awesome-phonenumber": "^3.3.0",
"axios": "^0.27.2",
"baileys-bottle": "^1.0.1",
"file-type": "^18.0.0",
"formdata-node": "^5.0.0",
"human-readable": "^0.2.1",
"jimp": "^0.16.2",
"jsdom": "^20.0.0",
"link-preview-js": "^2.1.13",
"lodash": "^4.17.21",
"moment-timezone": "^0.5.37",
"node-fetch": "^3.2.10",
"node-cache": "^5.1.2",
"node-cron": "^3.0.1",
"node-fetch": "^3.2.10",
"perf_hooks": "^0.0.1",
"pino": "^8.5.0",
"pino-pretty": "^9.1.0",
"qrcode": "1.5.1",
"qrcode-terminal": "^0.12.0",
"reflect-metadata": "^0.1.13",
"sqlite": "^4.1.2",
"sqlite3": "^5.1.1",
"typeorm": "^0.3.10",
"uuid": "^9.0.0",
"uuid-by-string": "^4.0.0",
"wa-sticker-formatter": "^4.3.2"
},
"devDependencies": {
Expand All @@ -109,13 +117,14 @@
"@swc/cli": "0.1.57",
"@swc/core": "1.3.0",
"@swc/jest": "0.2.22",
"@types/ffmpeg": "^1.0.4",
"@types/jest": "29.0.2",
"@types/node": "16.11.58",
"@types/ffmpeg": "^1.0.4",
"@types/qrcode": "^1.5.0",
"@types/uuid": "^8.3.4",
"@types/ws": "^8.5.3",
"@typescript-eslint/eslint-plugin": "5.37.0",
"@typescript-eslint/parser": "5.37.0",
"@types/uuid": "^8.3.4",
"eslint": "8.23.1",
"eslint-config-prettier": "8.5.0",
"eslint-plugin-jest": "27.0.4",
Expand Down
1 change: 1 addition & 0 deletions src/core/database/entities/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './instance.entity';
33 changes: 33 additions & 0 deletions src/core/database/entities/instance.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

import { WhatsappiOptions } from '../../interfaces';

@Entity('instances')
export class Instance {
@PrimaryGeneratedColumn()
id!: string;

@Column({ nullable: false })
sessionId!: string;

@Column({ nullable: false })
sessionName!: string;

@Column({ nullable: false })
sessionToken!: string;

@Column({ nullable: true })
webhookUrl?: string;

@Column({ nullable: false })
restartable!: boolean;

@Column({ nullable: true })
qrCode?: string;

@Column({ nullable: false, type: 'simple-json' })
options!: WhatsappiOptions;

@Column()
connectionStatus!: string;
}
137 changes: 137 additions & 0 deletions src/core/database/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { DataSource } from 'typeorm';

import BaileysBottle from 'baileys-bottle';
import StoreHandle from 'baileys-bottle/lib/bottle/StoreHandle';
import AuthHandle from 'baileys-bottle/lib/bottle/AuthHandle';

import { cwd } from 'process';

import { InstanceConnectionStatus } from '../interfaces/instance.interface';
import { WhatsappiOptions } from '../interfaces/whatsappi.interface';
import { generateUUID, generateUUIDFromString } from '../utils/global.util';

import { Instance } from './entities';

export class DatabaseModule {
private whatsappiOptions: WhatsappiOptions;
private databaseName: string;
private options:
| {
sync?: boolean | undefined;
debug?: boolean | undefined;
}
| undefined;
private whatsappiDataStore: DataSource | null = null;
constructor(
whatsappiOptions: WhatsappiOptions,
options?: {
sync?: boolean;
debug?: boolean;
},
) {
console.log('Database module initialized');
// Validate wharsappiOptions
whatsappiOptions.sessionId = whatsappiOptions.sessionId || generateUUID();
whatsappiOptions.sessionName = whatsappiOptions.sessionName || 'default';
whatsappiOptions.sessionToken =
whatsappiOptions.sessionToken ||
generateUUIDFromString(
`${whatsappiOptions.sessionId}${whatsappiOptions.sessionName}`,
);
whatsappiOptions.printQRinTerminal =
whatsappiOptions.printQRinTerminal || true;
whatsappiOptions.markOnlineOnConnect =
whatsappiOptions.markOnlineOnConnect || false;
whatsappiOptions.syncFullHistory = whatsappiOptions.syncFullHistory || true;
whatsappiOptions.restartable = whatsappiOptions.restartable || true;
whatsappiOptions.markOnlineOnConnect =
whatsappiOptions.markOnlineOnConnect || false;
whatsappiOptions.webhookUrl = whatsappiOptions.webhookUrl || undefined;
whatsappiOptions.ignoreBroadcastMessages =
whatsappiOptions.ignoreBroadcastMessages || false;
whatsappiOptions.ignoreGroupMessages =
whatsappiOptions.ignoreGroupMessages || false;
whatsappiOptions.ignoreServerAck =
whatsappiOptions.ignoreServerAck || false;
this.whatsappiOptions = whatsappiOptions;
this.options = options;
// Create new BaileysBottle
const databaseName = `${whatsappiOptions.sessionId}.db`;
this.databaseName = databaseName;
}

public init = async (): Promise<{
auth: AuthHandle;
store: StoreHandle;
}> => {
const ds = await new DataSource({
type: 'sqlite',
database: cwd() + `/db/whatsappi.db`,
entities: [Instance],
migrations: [],
synchronize: this.options?.sync || true,
logging: this.options?.debug || true,
}).initialize();
this.whatsappiDataStore = ds;

try {
const instanceRepository = ds.getRepository(Instance);
const instance = await instanceRepository.findOne({
where: {
sessionId: this.whatsappiOptions.sessionId,
},
});
if (!instance) {
await instanceRepository.save({
sessionId: this.whatsappiOptions.sessionId,
sessionName: this.whatsappiOptions.sessionName,
sessionToken: this.whatsappiOptions.sessionToken,
webhookUrl: this.whatsappiOptions.webhookUrl,
restartable: this.whatsappiOptions.restartable,
qrCode: '',
options: this.whatsappiOptions,
connectionStatus: InstanceConnectionStatus.CREATED,
});
}
} catch (error) {
new DatabaseModule(this.whatsappiOptions, {
...this.options,
sync: true,
}).init();
}
const { auth, store } = await BaileysBottle({
type: 'sqlite',
database: cwd() + `/db/${this.databaseName}`, // (optional) path to the
});
return {
auth,
store,
};
};

public getWhatsappiDataStore = (): DataSource => {
if (!this.whatsappiDataStore) {
throw new Error('Whatsappi data store not initialized');
}
return this.whatsappiDataStore;
};

public getWhatsappiOptions = (): WhatsappiOptions => {
return this.whatsappiOptions;
};

public getDatabaseName = (): string => {
return this.databaseName;
};

public getOptions = ():
| {
sync?: boolean | undefined;
debug?: boolean | undefined;
}
| undefined => {
return this.options;
};
}

export * from './entities';
1 change: 1 addition & 0 deletions src/core/interfaces/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './instance.interface';
export * from './whatsappi.interface';
19 changes: 19 additions & 0 deletions src/core/interfaces/instance.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Whatsappi } from '../whatsappi';

/**
* Connection status for instances
*/
export enum InstanceConnectionStatus {
CREATED = 'CREATED',
INITIALIZING = 'INITIALIZING',
WAITING_FOR_QR = 'WAITING_FOR_QR',
CONNECTED = 'CONNECTED',
DISCONNECTED = 'DISCONNECTED',
}

export interface EventEntry {
event: string;
callback: (...args: any[]) => void;
}

export type WhatsappiT = InstanceType<typeof Whatsappi>;
125 changes: 42 additions & 83 deletions src/core/interfaces/whatsappi.interface.ts
Original file line number Diff line number Diff line change
@@ -1,90 +1,49 @@
import { Contact, MessageUpsertType, proto } from '@adiwajshing/baileys';
import { UserFacingSocketConfig, WASocket } from '@adiwajshing/baileys';

export interface MessagesType {
messages: proto.IWebMessageInfo[];
type: MessageUpsertType;
fileNameDownloaded?: string;
}
import StoreHandle from 'baileys-bottle/lib/bottle/StoreHandle';

export interface ITypeDeviceWithMessage {
typeDevice: string;
message: proto.WebMessageInfo;
}
import { DataSource } from 'typeorm';

export interface WhatsappiProps {
/**
* Interface for new Whatsappi options
*/
export interface WhatsappiOptions {
sessionId?: string;
sessionName: string;
agentName?: string;
qrCodeInTerminal: boolean;
IgnoreBroadCastMessages: boolean;
IgnoreGroupsMessages: boolean;
IgnoreServer_ACK: boolean;
onMessage: (message: MessagesType) => void;
onStatusChange: (connectionStatus: 'Connected' | 'WaitinLogin') => void;
onDisconnected: () => void;
}

export interface IExistenceOnWhatsApp {
exists: boolean;
formatedJid: string;
}

export interface IListMessageDefinitions {
text: string;
footer?: string;
title: string;
buttonText: string;
sections: Array<{
title: string;
rows: Array<{
title: string;
rowId: string;
description?: string;
}>;
}>;
sessionToken?: string;
webhookUrl?: string;
restartable?: boolean;
printQRinTerminal?: boolean;
markOnlineOnConnect?: boolean;
ignoreBroadcastMessages?: boolean;
ignoreGroupMessages?: boolean;
ignoreServerAck?: boolean;
syncFullHistory?: boolean;
}

export interface IWhatsappi {
verifyExistenceNumber: (number: string) => Promise<IExistenceOnWhatsApp>;
sendGifOrVideoMessage: (
mediaPath: string,
number: string,
content?: string,
isGif?: boolean,
) => Promise<proto.WebMessageInfo>;
sendImage: (
imagePath: string,
number: string,
content?: string,
) => Promise<proto.WebMessageInfo>;
sendAudioMedia: (
audioPath: string,
number: string,
isPtt?: boolean,
) => Promise<proto.WebMessageInfo>;
logOut: () => Promise<boolean>;
sendListMessage: (
number: string,
listMessage: IListMessageDefinitions,
) => Promise<proto.WebMessageInfo>;
getDeviceInformation: () => Contact;
blockContact: (number: string) => Promise<boolean>;
unBlockContact: (number: string) => Promise<boolean>;
getImageContact: (
number: string,
isGroup: boolean,
) => Promise<{ uri: string }>;
deleteMessageForEveryone: (
number: string,
messageId: string,
isGroup?: boolean,
) => Promise<boolean>;
sendSimpleMessage: (
content: string,
number: string,
) => Promise<proto.WebMessageInfo>;
replyMessage: (
number: string,
content: string,
quotedId: string,
) => Promise<proto.WebMessageInfo>;
/**
* Interface for Whatsappi instance
* @interface
* @property {WhatsappiOptions} instanceOptions - Instance options
* @property {DataSource} whatsappiDatabase - Instance database
* @property {UserFacingSocketConfig} socketOptions - Instance socket options
* @property {WASocket} socket - Instance socket
* @property {StoreHandle} store - Instance store
* @property {StoreHandle} getStore - Instance getStore
* @property {Function} onQRUpdate - Instance onQRUpdate
* @property {Function} onQRScanned - Instance onQRScanned
* @property {Function} onLoggedIn - Instance onLoggedIn
* @property {Function} onEvent - Instance onEvent
*/
export interface WhatsappiInstance {
instanceOptions: WhatsappiOptions;
whatsappiDatabase: DataSource;
socketOptions: UserFacingSocketConfig;
socket: WASocket;
store: StoreHandle;
getStore: StoreHandle;
onQRUpdate: (callback: (qr: string) => void) => void;
onQRScanned: (callback: () => void) => void;
onLoggedIn: (callback: () => void) => void;
onEvent: (event: string, cb: any) => void;
}
Loading

0 comments on commit 172c0ae

Please sign in to comment.