Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
vanbasten17 committed Oct 14, 2021
1 parent e16d3f3 commit 8aa288a
Show file tree
Hide file tree
Showing 29 changed files with 581 additions and 429 deletions.
15 changes: 7 additions & 8 deletions packages/botonic-api/src/rest/routes/events.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BotonicEvent, MessageEventAck } from '@botonic/core'
import { BotonicEvent, MessageEventAck, PROVIDER } from '@botonic/core'
import { dataProviderFactory } from '@botonic/core/lib/esm/data-provider'
import { Router } from 'express'
import jwt from 'express-jwt'
Expand Down Expand Up @@ -76,11 +76,10 @@ export default function eventsRouter(args: any): Router {
const { userId } = req.user
const { message, sender } = req.body
let user = await dp.getUser(userId)
user = await dp.updateUser({
...user,
session: JSON.stringify({ user: sender }),
})
const updatedUser = { ...user, ...sender }
user = await dp.updateUser(updatedUser)
// TODO: Next iterations: We should receive an event with userId and eventId from frontend
// TODO: Only update ack for webchat
const webchatMsgId = message.id
await handlers.run('sender', {
events: [
Expand All @@ -92,9 +91,9 @@ export default function eventsRouter(args: any): Router {
websocketId: user.websocketId,
})
await handlers.run('botExecutor', {
input: message,
session: JSON.parse(user.session),
lastRoutePath: user.route,
input: { ...message, userId }, // To identify user executing the input
session: updatedUser.session,
botState: user.botState,
websocketId: user.websocketId,
})
} catch (e) {
Expand Down
57 changes: 37 additions & 20 deletions packages/botonic-core/src/core-bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
BotonicEvent,
BotRequest,
BotResponse,
BotState,
Locales,
MessageEventAck,
MessageEventFrom,
Expand Down Expand Up @@ -81,26 +82,30 @@ export class CoreBot {
)
}

getString(id: string, session: Session): string {
// @ts-ignore
return getString(this.locales, session.__locale, id)
getString(id: string, botState: BotState): string {
if (!botState.locale) {
console.error('Locale is not defined')
return ''
}
return getString(this.locales, botState.locale, id)
}

setLocale(locale: string, session: Session): void {
session.__locale = locale
setLocale(locale: string, botState: BotState): void {
botState.locale = locale
}

async input({
input,
session,
lastRoutePath,
botState,
dataProvider,
}: BotRequest): Promise<BotResponse> {
session = session || {}
if (!session.__locale) session.__locale = 'en'
if (!botState.locale) botState.locale = 'en'
// @ts-ignore
const userId = input.userId

const parsedUserEvent = this.botonicOutputParser.inputToBotonicEvent(input)

const parsedUserEvent = this.botonicOutputParser.parseFromUserInput(input)
const userId = session.user.id
if (dataProvider) {
// TODO: Next iterations. Review cycle of commited events to DB when messages change their ACK
// @ts-ignore
Expand All @@ -120,7 +125,7 @@ export class CoreBot {
'pre',
input,
session,
lastRoutePath,
botState,
undefined,
undefined,
dataProvider
Expand All @@ -133,7 +138,7 @@ export class CoreBot {
...(await getComputedRoutes(this.routes, {
input,
session,
lastRoutePath,
botState,
})),
...this.defaultRoutes,
],
Expand All @@ -144,18 +149,18 @@ export class CoreBot {
const output = (this.router as Router).processInput(
input,
session,
lastRoutePath
botState
)
const request = {
getString: stringId => this.getString(stringId, session),
setLocale: locale => this.setLocale(locale, session),
getString: stringId => this.getString(stringId, botState),
setLocale: locale => this.setLocale(locale, botState),
session: session || {},
params: output.params || {},
input: input,
plugins: this.plugins,
defaultTyping: this.defaultTyping,
defaultDelay: this.defaultDelay,
lastRoutePath,
botState,
dataProvider,
}

Expand All @@ -170,14 +175,15 @@ export class CoreBot {
console.error(e)
}

lastRoutePath = output.lastRoutePath
botState.lastRoutePath = output.botState.lastRoutePath

if (this.plugins) {
await runPlugins(
this.plugins,
'post',
input,
session,
lastRoutePath,
botState,
response,
messageEvents,
dataProvider
Expand All @@ -199,13 +205,24 @@ export class CoreBot {
}
}

session.is_first_interaction = false
botState.isFirstInteraction = false

if (dataProvider) {
const user = dataProvider.getUser(userId)
if (!user) {
// throw error
} else {
// @ts-ignore
dataProvider.updateUser({ ...user, session, botState })
}
}

return {
input,
response,
messageEvents,
session,
lastRoutePath,
botState,
dataProvider,
}
}
Expand Down
8 changes: 4 additions & 4 deletions packages/botonic-core/src/hubtype-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import axios, { AxiosResponse } from 'axios'
import Pusher, { AuthOptions, Channel } from 'pusher-js'
import Channels from 'pusher-js/types/src/core/channels/channels'

import { Input, SessionUser } from './models'
import { Input } from './models'
import { getWebpackEnvVar } from './utils'

interface UnsentInput {
Expand All @@ -21,7 +21,7 @@ interface ServerConfig {
}
interface HubtypeServiceArgs {
appId: string
user: SessionUser
user: any
lastMessageId: string
lastMessageUpdateDate: string
onEvent: any
Expand Down Expand Up @@ -50,7 +50,7 @@ const PONG_TIMEOUT = 5 * 1000 // https://pusher.com/docs/channels/using_channels
*/
export class HubtypeService {
appId: string
user: SessionUser
user: any
lastMessageId: string
lastMessageUpdateDate: string
onEvent: any
Expand Down Expand Up @@ -213,7 +213,7 @@ export class HubtypeService {
/**
* @return {Promise<void>}
*/
async postMessage(user: SessionUser, message: any): Promise<void> {
async postMessage(user: any, message: any): Promise<void> {
try {
// @ts-ignore
await this.init(user)
Expand Down
11 changes: 11 additions & 0 deletions packages/botonic-core/src/models/bot-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { RoutePath } from './legacy-types'

export interface BotState {
botId: string
isFirstInteraction: boolean
isHandoff: boolean
isShadowing: boolean
lastRoutePath: RoutePath
locale?: string
retries: number
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,6 @@ export interface BotonicMessageEvent extends BaseEvent {
type: MessageEventTypes
typing: number
delay: number
// idFromChannel?:string references to msgId
// also channel
}
2 changes: 2 additions & 0 deletions packages/botonic-core/src/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from './bot-state'
export * from './events'
export * from './legacy-types'
export * from './session'
export * from './user'
38 changes: 4 additions & 34 deletions packages/botonic-core/src/models/legacy-types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// TODO: This file contains all the legacy types we had in index.ts. After some refactors, we should be able to get rid of many of them.

import { DataProvider } from '../data-provider'
import { BotState } from './bot-state'
import { BotonicEvent } from './events'
import { Session } from './session'

export type CaseStatusType =
| typeof CASE_STATUS.ATTENDING
Expand Down Expand Up @@ -131,37 +132,6 @@ export type ProviderType =
| typeof PROVIDER.WECHAT
| typeof PROVIDER.WHATSAPP

export interface SessionUser {
id: string
// login
username?: string
// person name
name?: string
// whatsapp, telegram,...
provider: ProviderType
// The provider's user id
extra_data?: any
imp_id?: string
provider_id?: string
}

// eslint-disable @typescript-eslint/naming-convention
export interface Session {
bot: {
id: string
name?: string
}
__locale?: string
__retries: number
is_first_interaction: boolean
last_session?: any
organization?: string
user: SessionUser
// after handoff
_hubtype_case_status?: CaseStatusType
_hubtype_case_typification?: string
_shadowing?: boolean
}
// eslint-enable @typescript-eslint/naming-convention

export type InputMatcher = (input: Input) => boolean
Expand Down Expand Up @@ -204,8 +174,8 @@ export type Routes<R = Route> = R[] | ((_: BotRequest) => R[])

export interface BotRequest {
input: Input
lastRoutePath: RoutePath
session: Session
botState: BotState
dataProvider?: DataProvider
}

Expand Down Expand Up @@ -255,7 +225,7 @@ export interface ProcessInputResult {
action: Action
emptyAction: Action
fallbackAction: Action
lastRoutePath: RoutePath
botState: BotState
params: Params
}

Expand Down
3 changes: 3 additions & 0 deletions packages/botonic-core/src/models/session.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface Session {
[key: string]: any
}
15 changes: 11 additions & 4 deletions packages/botonic-core/src/models/user.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { Session } from './legacy-types'
import { BotState } from './bot-state'
import { Session } from './session'

export interface User {
id: string //TODO: UUID
providerId?: string
websocketId?: string
name?: string
userName?: string
channel: string
idFromChannel: string // providerId
session: Session
route: string
botState: BotState
// functioning
isOnline: boolean
websocketId?: string
// part of details?
// route: string inside botState
locationInfo: string
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class BotonicOutputParser {
* to be saved. This is, converting a botonic input like: '{id: 'msgId', data: 'rawData', payload: 'somePayload'}'
* into a BotonicEvent with the expected properties.
*/
parseFromUserInput(input: any): Partial<BotonicEvent> {
inputToBotonicEvent(input: any): Partial<BotonicEvent> {
return this.factory.parse(input)
}

Expand Down
15 changes: 11 additions & 4 deletions packages/botonic-core/src/plugins.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { DataProvider } from './data-provider'
import { BotonicEvent, Input, PluginConfig, RoutePath, Session } from './models'
import {
BotonicEvent,
BotState,
Input,
PluginConfig,
RoutePath,
Session,
} from './models'

type PluginMode = 'pre' | 'post'

Expand All @@ -26,7 +33,7 @@ export async function runPlugins(
mode: PluginMode,
input: Input,
session: Session,
lastRoutePath: RoutePath,
botState: BotState,
response: string | null = null,
messageEvents: Partial<BotonicEvent>[] | null = null,
dataProvider?: DataProvider
Expand All @@ -35,12 +42,12 @@ export async function runPlugins(
const p = await plugins[key]
try {
if (mode === 'pre')
await p.pre({ input, session, lastRoutePath, dataProvider })
await p.pre({ input, session, botState, dataProvider })
if (mode === 'post')
await p.post({
input,
session,
lastRoutePath,
botState,
response,
messageEvents,
dataProvider,
Expand Down
Loading

0 comments on commit 8aa288a

Please sign in to comment.