Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(messenger): messenger v1 #329

Merged
merged 41 commits into from
Jan 29, 2022
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
7e1be72
delete old
samuelmasse Jan 25, 2022
7e24136
use legacy
samuelmasse Jan 25, 2022
dee4dfa
remove deps
samuelmasse Jan 25, 2022
6442a12
Merge branch 'master' into sm-channels-v2
samuelmasse Jan 26, 2022
98f1bce
use channels 0.1.0
samuelmasse Jan 26, 2022
2e350e9
bring changes
samuelmasse Jan 26, 2022
8825394
gif
samuelmasse Jan 26, 2022
cf8aad6
bring changes
samuelmasse Jan 26, 2022
3b87577
fix
samuelmasse Jan 26, 2022
49e8ae3
fix
samuelmasse Jan 26, 2022
160c2ef
bring changes
samuelmasse Jan 26, 2022
6a79deb
rewire comment
samuelmasse Jan 28, 2022
ed8d371
fix
samuelmasse Jan 28, 2022
fbbc10f
Merge branch 'master' into sm-channels-v2
samuelmasse Jan 28, 2022
538cc6a
start
samuelmasse Jan 28, 2022
ba953cd
message reception
samuelmasse Jan 28, 2022
baaa306
fix
samuelmasse Jan 28, 2022
5accf74
send text
samuelmasse Jan 28, 2022
ff78006
refact
samuelmasse Jan 28, 2022
18dd3b8
readme
samuelmasse Jan 28, 2022
e439100
image
samuelmasse Jan 28, 2022
e372e33
single-choice
samuelmasse Jan 28, 2022
181aa5b
Merge branch 'master' into sm-channels-v2
samuelmasse Jan 28, 2022
dd4155a
Merge branch 'sm-channels-v2' into sm-messenger-v2
samuelmasse Jan 28, 2022
0286604
fix
samuelmasse Jan 28, 2022
32e7d9e
bring changes
samuelmasse Jan 28, 2022
bb85c82
Merge branch 'sm-channels-v2' into sm-messenger-v2
samuelmasse Jan 28, 2022
744ecd7
bump
samuelmasse Jan 28, 2022
2b87c8a
Merge branch 'sm-channels-v2' into sm-messenger-v2
samuelmasse Jan 28, 2022
4caa3cc
Merge branch 'master' into sm-messenger-v2
samuelmasse Jan 28, 2022
b6fd2f6
fix merge
samuelmasse Jan 28, 2022
14e9c6c
Merge branch 'master' into sm-messenger-v2
samuelmasse Jan 29, 2022
0f02324
Merge branch 'master' into sm-messenger-v2
samuelmasse Jan 29, 2022
864413e
use channel in server
samuelmasse Jan 29, 2022
ec64535
quick_reply
samuelmasse Jan 29, 2022
25e6a3f
carousel
samuelmasse Jan 29, 2022
556514f
refact
samuelmasse Jan 29, 2022
76ea3f3
fix
samuelmasse Jan 29, 2022
e5c9ec3
audio video location
samuelmasse Jan 29, 2022
7f2e592
file
samuelmasse Jan 29, 2022
e0e2389
readme
samuelmasse Jan 29, 2022
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
63 changes: 46 additions & 17 deletions packages/channels/example/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,49 @@ import clc from 'cli-color'
import { Router } from 'express'
import { Channel } from '../src/base/channel'
import { MessengerChannel } from '../src/messenger/channel'
import { SlackChannel } from '../src/slack/channel'
import { SmoochChannel } from '../src/smooch/channel'
import { TeamsChannel } from '../src/teams/channel'
import { TelegramChannel } from '../src/telegram/channel'
import { TwilioChannel } from '../src/twilio/channel'
import { VonageChannel } from '../src/vonage/channel'
import payloads from './payloads.json'

export class App {
constructor(private router: Router, private config: any) {}

async setup() {
await this.setupChannel('telegram', new TelegramChannel())
await this.setupChannel('twilio', new TwilioChannel())
await this.setupChannel('smooch', new SmoochChannel())
await this.setupChannel('teams', new TeamsChannel())
await this.setupChannel('slack', new SlackChannel())
await this.setupChannel('messenger', new MessengerChannel())
await this.setupChannel('vonage', new VonageChannel())
}

async setupChannel(name: string, channel: Channel) {
await channel.setup(this.router)
await channel.setup(this.router, {
info: (message: string, data?: any) => {
// eslint-disable-next-line no-console
console.log(message, data)
},
debug: (message: string, data?: any) => {
console.debug(message, data)
},
warn: (message: string, data?: any) => {
console.warn(message, data)
},
error: (error: Error, message?: string, data?: any) => {
console.error(message, error?.message, (<any>error).response?.data, data)
}
})

channel.on('message', async ({ scope, endpoint, content }) => {
this.log('message', name, scope, { endpoint, content })

const respond = async () => {
try {
for (const payload of payloads) {
await channel.send(scope, endpoint, payload)
if (content.type === 'say_something') {
await channel.send(scope, endpoint, { type: 'text', text: `Say Something: ${content.text}` })
} else if (content.type === 'postback') {
await channel.send(scope, endpoint, { type: 'text', text: `Postback: ${content.payload}` })
} else if (content.type === 'quick_reply') {
await channel.send(scope, endpoint, { type: 'text', text: `Quick Reply: ${content.text}` })
} else if (content.text?.startsWith('test')) {
for (const payload of this.filterResponsePayloads(payloads, content.text)) {
await channel.send(scope, endpoint, payload)
}
} else {
await channel.send(scope, endpoint, { type: 'text', text: 'OK', typing: true })
}
} catch (e) {
console.error('Error occurred sending message', e)
Expand All @@ -48,13 +60,30 @@ export class App {

for (const [key, val] of Object.entries<any>(this.config.scopes)) {
if (val[name]) {
await channel.start(key, val[name])
this.log('conf', name, key, val[name])
const { error } = channel.meta.schema.validate(val[name])
if (error) {
this.log('conf-err', name, key, error.message)
} else {
await channel.start(key, val[name])
await channel.initialize(key)
this.log('conf', name, key, val[name])
}
}
}
}

private log(type: string, channel: string, context: string, obj: any) {
console.info(clc.blue(type), clc.bold(channel), context, obj)
}

private filterResponsePayloads(payloads: any[], filter: string) {
const filtered = []
for (const payload of payloads) {
if (filter?.includes(payload.type)) {
filtered.push(payload)
}
}

return filtered.length ? filtered : payloads
}
}
51 changes: 50 additions & 1 deletion packages/channels/example/payloads.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
"image": "https://upload.wikimedia.org/wikipedia/commons/a/a1/Mallard2.jpg",
"typing": true
},
{
"type": "image",
"title": "YOU SHALL NOT PASS",
"image": "https://digginginthedirt.de/photos/upload/2018/05/26/20180526172235-15859610.gif",
"typing": true
},
{
"type": "card",
"title": "A banana card",
Expand Down Expand Up @@ -80,12 +86,55 @@
}
]
},
{
"type": "file",
"title": "here is a zip of the 1.0.0 messaging codebase",
"file": "https://github.com/botpress/messaging/archive/refs/tags/v1.0.0.zip",
"typing": true
},
{
"type": "video",
"title": "look at the big bunny video",
"video": "https://www.w3schools.com/html/mov_bbb.mp4",
"typing": true
},
{
"type": "audio",
"title": "this is audio of a horse",
"audio": "https://www.w3schools.com/html/horse.mp3",
"typing": true
},
{
"type": "location",
"title": "this is the location of my house",
"address": "1600 Pennsylvania Avenue NW, Washington, DC 20500, États-Unis",
"latitude": 38.89764765487744,
"longitude": -77.03709704833226,
"typing": true
},
{
"type": "dropdown",
"message": "Pick something :",
"options": [
{ "label": "Mars", "value": "planet_mars" },
{ "label": "Venus", "value": "planet_venus" },
{ "label": "Jupiter", "value": "planet_jupiter" },
{ "label": "Mars2", "value": "planet_mars2" },
{ "label": "Venus2", "value": "planet_venus2" },
{ "label": "Jupiter2", "value": "planet_jupiter2" },
{ "label": "Mars3", "value": "planet_mars3" },
{ "label": "Venus3", "value": "planet_venus3" },
{ "label": "Jupiter3", "value": "planet_jupiter3" }
],
"typing": true
},
{
"type": "single-choice",
"text": "Make a choice :",
"choices": [
{ "title": "Yay", "value": "YES" },
{ "title": "Nay", "value": "NO" }
]
],
"typing": true
}
]
12 changes: 1 addition & 11 deletions packages/channels/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@botpress/messaging-channels",
"version": "0.1.0",
"version": "0.2.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"source": "src/index.ts",
Expand All @@ -25,23 +25,13 @@
"@types/uuid": "^8.3.4"
},
"dependencies": {
"@slack/events-api": "^2.3.2",
"@slack/interactive-messages": "^1.5.0",
"@slack/rtm-api": "^5.0.3",
"@slack/web-api": "^5.8.0",
"@vonage/server-sdk": "2.10.7-beta-2",
"axios": "^0.24.0",
"botbuilder": "^4.14.1",
"cli-color": "^2.0.1",
"express": "^4.17.2",
"joi": "^17.5.0",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.21",
"lru-cache": "^6.0.0",
"ms": "^2.1.3",
"smooch-core": "^8.11.4",
"telegraf": "^3.27.1",
"twilio": "^3.67.0",
"uuid": "^8.3.2",
"yn": "^4.0.0"
}
Expand Down
17 changes: 1 addition & 16 deletions packages/channels/src/base/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import clc from 'cli-color'
import { Request, Router, Response, RequestHandler, NextFunction } from 'express'
import yn from 'yn'
import { Logger } from './logger'
import { ChannelService } from './service'

Expand All @@ -14,22 +12,9 @@ export class ChannelApi<TService extends ChannelService<any, any>> {
makeUrl(callback: (scope: string) => Promise<string>) {
this.urlCallback = callback
}

protected async printWebhook(scope: string, name: string, path?: string) {
// TODO: remove this dependency on server env vars
if (yn(process.env.SPINNED)) {
const externalUrl = await this.urlCallback!(scope)

this.service.logger?.info(
`[${scope}] ${clc.bold(name.charAt(0).toUpperCase() + name.slice(1))}${
path ? ' ' + path : ''
} webhook ${clc.blackBright(`${externalUrl}/${name}${path ? `/${path}` : ''}`)}`
)
}
}
}

export type Middleware<T> = (req: T, res: Response, next: NextFunction) => Promise<void>
export type Middleware<T> = (req: T, res: Response, next: NextFunction) => Promise<any>

export class ChannelApiManager {
constructor(private service: ChannelService<any, any>, private router: Router, private logger?: Logger) {}
Expand Down
1 change: 1 addition & 0 deletions packages/channels/src/base/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export abstract class ChannelTemplate<
constructor(public readonly service: TService, public readonly api: TApi, public readonly stream: TStream) {}

async setup(router: Router, logger?: Logger) {
this.logger = logger
await this.service.setup()
await this.api.setup(new ChannelApiManager(this.service, router, logger))
await this.stream.setup()
Expand Down
2 changes: 1 addition & 1 deletion packages/channels/src/base/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type ChannelContext<TState extends ChannelState<any>> = {
export interface IndexChoiceOption {
type: IndexChoiceType
title: string
value: string
value?: string
}

export enum IndexChoiceType {
Expand Down
21 changes: 21 additions & 0 deletions packages/channels/src/base/renderers/audio.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ChannelRenderer } from '../../base/renderer'
import { AudioContent } from '../../content/types'
import { ChannelContext } from '../context'

export abstract class AudioRenderer implements ChannelRenderer<any> {
get priority(): number {
return 0
}

handles(context: ChannelContext<any>): boolean {
const payload = context.payload as AudioContent
return !!payload.audio
}

render(context: ChannelContext<any>) {
const payload = context.payload as AudioContent
this.renderAudio(context, payload)
}

abstract renderAudio(context: ChannelContext<any>, payload: AudioContent): void
}
21 changes: 21 additions & 0 deletions packages/channels/src/base/renderers/file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ChannelRenderer } from '../../base/renderer'
import { FileContent } from '../../content/types'
import { ChannelContext } from '../context'

export abstract class FileRenderer implements ChannelRenderer<any> {
get priority(): number {
return 0
}

handles(context: ChannelContext<any>): boolean {
const payload = context.payload as FileContent
return !!payload.file
}

render(context: ChannelContext<any>) {
const payload = context.payload as FileContent
this.renderFile(context, payload)
}

abstract renderFile(context: ChannelContext<any>, payload: FileContent): void
}
21 changes: 21 additions & 0 deletions packages/channels/src/base/renderers/location.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ChannelRenderer } from '../../base/renderer'
import { LocationContent } from '../../content/types'
import { ChannelContext } from '../context'

export abstract class LocationRenderer implements ChannelRenderer<any> {
get priority(): number {
return 0
}

handles(context: ChannelContext<any>): boolean {
const payload = context.payload as LocationContent
return !!payload.latitude && !!payload.longitude
}

render(context: ChannelContext<any>) {
const payload = context.payload as LocationContent
this.renderLocation(context, payload)
}

abstract renderLocation(context: ChannelContext<any>, payload: LocationContent): void
}
21 changes: 21 additions & 0 deletions packages/channels/src/base/renderers/video.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { VideoContent } from '../../content/types'
import { ChannelContext } from '../context'
import { ChannelRenderer } from '../renderer'

export abstract class VideoRenderer implements ChannelRenderer<any> {
get priority(): number {
return 0
}

handles(context: ChannelContext<any>): boolean {
const payload = context.payload as VideoContent
return !!payload.video
}

render(context: ChannelContext<any>) {
const payload = context.payload as VideoContent
this.renderVideo(context, payload)
}

abstract renderVideo(context: ChannelContext<any>, payload: VideoContent): void
}
3 changes: 0 additions & 3 deletions packages/channels/src/base/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,6 @@ export abstract class ChannelService<
if (index) {
const key = this.getIndexCacheKey(scope, identity, sender)
const options = this.cacheIndexResponses.get(key)

this.cacheIndexResponses.del(key)

const option = options?.[index - 1]

if (option) {
Expand Down
7 changes: 0 additions & 7 deletions packages/channels/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,2 @@
export * from './base/channel'
export * from './base/endpoint'
export * from './messenger/channel'
export * from './slack/channel'
export * from './smooch/channel'
export * from './teams/channel'
export * from './telegram/channel'
export * from './twilio/channel'
export * from './vonage/channel'
28 changes: 28 additions & 0 deletions packages/channels/src/messenger/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
### Sending

| Channels | Twilio |
| -------- | :----: |
| Text | ✅ |
| Image | ❌ |
| Choice | ❌ |
| Dropdown | ❌ |
| Card | ❌ |
| Carousel | ❌ |
| File | ❌ |
| Audio | ❌ |
| Video | ❌ |
| Location | ❌ |

### Receiving

| Channels | Twilio |
| ------------- | :----: |
| Text | ✅ |
| Postback | ❌ |
| Say Something | ❌ |
| Voice | ❌ |
| Image | ❌ |
| File | ❌ |
| Audio | ❌ |
| Video | ❌ |
| Location | ❌ |
Loading