mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-08 00:26:37 +08:00
chore(message-gateway): swagger and format
This commit is contained in:
@@ -24,7 +24,10 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from '@/components/ui/select';
|
} from '@/components/ui/select';
|
||||||
import { TelegramForm, type TelegramFormValue } from '../channels/telegram/form';
|
import {
|
||||||
|
TelegramForm,
|
||||||
|
type TelegramFormValue,
|
||||||
|
} from '../channels/telegram/form';
|
||||||
import { QQForm, type QQFormValue } from '../channels/qq/form';
|
import { QQForm, type QQFormValue } from '../channels/qq/form';
|
||||||
import type { CreateMessageChannelRequest } from '@/lib/services/message-gateway';
|
import type { CreateMessageChannelRequest } from '@/lib/services/message-gateway';
|
||||||
|
|
||||||
@@ -66,7 +69,9 @@ export function AddChannelDialog({
|
|||||||
const canSubmit =
|
const canSubmit =
|
||||||
name.trim() !== '' &&
|
name.trim() !== '' &&
|
||||||
((type === 'telegram' && telegram.bot_token.trim() !== '') ||
|
((type === 'telegram' && telegram.bot_token.trim() !== '') ||
|
||||||
(type === 'qq' && qq.app_id.trim() !== '' && qq.app_secret.trim() !== ''));
|
(type === 'qq' &&
|
||||||
|
qq.app_id.trim() !== '' &&
|
||||||
|
qq.app_secret.trim() !== ''));
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
if (!canSubmit || !type) return;
|
if (!canSubmit || !type) return;
|
||||||
|
|||||||
@@ -39,8 +39,7 @@ export function ChannelCard({
|
|||||||
}: ChannelCardProps) {
|
}: ChannelCardProps) {
|
||||||
const t = useTranslations('admin.messageGateway');
|
const t = useTranslations('admin.messageGateway');
|
||||||
const [confirmOpen, setConfirmOpen] = React.useState(false);
|
const [confirmOpen, setConfirmOpen] = React.useState(false);
|
||||||
const typeLabel =
|
const typeLabel = channel.type === 'qq' ? t('typeQQ') : t('typeTelegram');
|
||||||
channel.type === 'qq' ? t('typeQQ') : t('typeTelegram');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='rounded-xl border bg-card p-4 space-y-4'>
|
<div className='rounded-xl border bg-card p-4 space-y-4'>
|
||||||
|
|||||||
@@ -119,7 +119,9 @@ export default function MessageGatewayAdminPage() {
|
|||||||
key={ch.id}
|
key={ch.id}
|
||||||
channel={ch}
|
channel={ch}
|
||||||
toggling={toggleMutation.isPending}
|
toggling={toggleMutation.isPending}
|
||||||
deleting={deleteMutation.isPending && deleteMutation.variables === ch.id}
|
deleting={
|
||||||
|
deleteMutation.isPending && deleteMutation.variables === ch.id
|
||||||
|
}
|
||||||
onToggle={(enabled) =>
|
onToggle={(enabled) =>
|
||||||
toggleMutation.mutate({ id: ch.id, enabled })
|
toggleMutation.mutate({ id: ch.id, enabled })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ export function BotBindingCard() {
|
|||||||
UserMessageGatewayService.bind({ channel_id: channelId, code }),
|
UserMessageGatewayService.bind({ channel_id: channelId, code }),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success(t('bindSuccess'));
|
toast.success(t('bindSuccess'));
|
||||||
queryClient.invalidateQueries({ queryKey: ['message-gateway', 'bindings'] });
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ['message-gateway', 'bindings'],
|
||||||
|
});
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
setChannelId('');
|
setChannelId('');
|
||||||
setCode('');
|
setCode('');
|
||||||
@@ -65,7 +67,9 @@ export function BotBindingCard() {
|
|||||||
mutationFn: (id: string) => UserMessageGatewayService.unbind(id),
|
mutationFn: (id: string) => UserMessageGatewayService.unbind(id),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success(t('unbindSuccess'));
|
toast.success(t('unbindSuccess'));
|
||||||
queryClient.invalidateQueries({ queryKey: ['message-gateway', 'bindings'] });
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: ['message-gateway', 'bindings'],
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onError: (err: unknown) => {
|
onError: (err: unknown) => {
|
||||||
toast.error(t('unbindFailed') + ': ' + (err as Error).message);
|
toast.error(t('unbindFailed') + ': ' + (err as Error).message);
|
||||||
@@ -82,8 +86,12 @@ export function BotBindingCard() {
|
|||||||
<Bot className='size-4' />
|
<Bot className='size-4' />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2 className='text-base font-semibold tracking-tight'>{t('title')}</h2>
|
<h2 className='text-base font-semibold tracking-tight'>
|
||||||
<p className='text-[11px] text-muted-foreground'>{t('description')}</p>
|
{t('title')}
|
||||||
|
</h2>
|
||||||
|
<p className='text-[11px] text-muted-foreground'>
|
||||||
|
{t('description')}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -165,7 +173,9 @@ export function BotBindingCard() {
|
|||||||
</Select>
|
</Select>
|
||||||
{!channelsQuery.isPending &&
|
{!channelsQuery.isPending &&
|
||||||
(channelsQuery.data ?? []).length === 0 ? (
|
(channelsQuery.data ?? []).length === 0 ? (
|
||||||
<p className='text-xs text-muted-foreground'>{t('noChannels')}</p>
|
<p className='text-xs text-muted-foreground'>
|
||||||
|
{t('noChannels')}
|
||||||
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className='space-y-2'>
|
<div className='space-y-2'>
|
||||||
|
|||||||
@@ -85,7 +85,11 @@ const adminItems: NavItem[] = [
|
|||||||
{ titleKey: 'storage', url: '/admin/files', icon: FolderOpen },
|
{ titleKey: 'storage', url: '/admin/files', icon: FolderOpen },
|
||||||
{ titleKey: 'database', url: '/admin/database', icon: Database },
|
{ titleKey: 'database', url: '/admin/database', icon: Database },
|
||||||
{ titleKey: 'push', url: '/admin/push', icon: Bell },
|
{ titleKey: 'push', url: '/admin/push', icon: Bell },
|
||||||
{ titleKey: 'messageGateway', url: '/admin/message-gateway', icon: MessagesSquare },
|
{
|
||||||
|
titleKey: 'messageGateway',
|
||||||
|
url: '/admin/message-gateway',
|
||||||
|
icon: MessagesSquare,
|
||||||
|
},
|
||||||
{ titleKey: 'logs', url: '/admin/logs', icon: Terminal },
|
{ titleKey: 'logs', url: '/admin/logs', icon: Terminal },
|
||||||
{ titleKey: 'system', url: '/admin/system', icon: ShieldCheck },
|
{ titleKey: 'system', url: '/admin/system', icon: ShieldCheck },
|
||||||
{ titleKey: 'adminSettings', url: '/admin/settings', icon: Settings },
|
{ titleKey: 'adminSettings', url: '/admin/settings', icon: Settings },
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ package message_gateway
|
|||||||
const (
|
const (
|
||||||
errNameRequired = "name is required"
|
errNameRequired = "name is required"
|
||||||
errTypeInvalid = "type must be telegram or qq"
|
errTypeInvalid = "type must be telegram or qq"
|
||||||
errTelegramTokenRequired = "bot_token is required"
|
errTelegramTokenRequired = "telegram bot secret is required" //nolint:gosec // user-facing validation text
|
||||||
errQQCredentialsRequired = "app_id and app_secret are required"
|
errQQCredentialsRequired = "qq app id and secret are required" //nolint:gosec // user-facing validation text
|
||||||
errChannelNotFound = "channel not found"
|
errChannelNotFound = "channel not found"
|
||||||
errChannelProbeFailed = "channel probe failed"
|
errChannelProbeFailed = "channel probe failed"
|
||||||
maskedSecret = "********"
|
maskedSecret = "********"
|
||||||
|
|||||||
@@ -318,8 +318,9 @@ func probeCredentials(ctx context.Context, typ string, creds, extra map[string]s
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer func() { _ = resp.Body.Close() }()
|
||||||
body, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
|
const probeBodyLimit = 4096
|
||||||
|
body, _ := io.ReadAll(io.LimitReader(resp.Body, probeBodyLimit))
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return fmt.Errorf("telegram getMe status %d", resp.StatusCode)
|
return fmt.Errorf("telegram getMe status %d", resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright 2026 Arctel.net
|
// Copyright 2026 Arctel.net
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package runner starts message-gateway adapters in the Worker process.
|
||||||
package runner
|
package runner
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ type gateway struct {
|
|||||||
node string
|
node string
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
running map[uint64]*runningChannel
|
running map[uint64]*runningChannel
|
||||||
seen map[uint64]time.Time
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *gateway) sync(ctx context.Context) error {
|
func (r *gateway) sync(ctx context.Context) error {
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ import (
|
|||||||
admin_push "github.com/Rain-kl/Wavelet/internal/apps/admin/push"
|
admin_push "github.com/Rain-kl/Wavelet/internal/apps/admin/push"
|
||||||
"github.com/Rain-kl/Wavelet/internal/apps/admin/push/custom_events"
|
"github.com/Rain-kl/Wavelet/internal/apps/admin/push/custom_events"
|
||||||
"github.com/Rain-kl/Wavelet/internal/apps/risk_control"
|
"github.com/Rain-kl/Wavelet/internal/apps/risk_control"
|
||||||
"github.com/Rain-kl/Wavelet/internal/listener"
|
|
||||||
"github.com/Rain-kl/Wavelet/internal/infra/config"
|
"github.com/Rain-kl/Wavelet/internal/infra/config"
|
||||||
taskhandlers "github.com/Rain-kl/Wavelet/internal/infra/task/handlers"
|
taskhandlers "github.com/Rain-kl/Wavelet/internal/infra/task/handlers"
|
||||||
|
"github.com/Rain-kl/Wavelet/internal/listener"
|
||||||
"github.com/Rain-kl/Wavelet/internal/model"
|
"github.com/Rain-kl/Wavelet/internal/model"
|
||||||
"github.com/Rain-kl/Wavelet/internal/platform/lifecycle"
|
"github.com/Rain-kl/Wavelet/internal/platform/lifecycle"
|
||||||
"github.com/Rain-kl/Wavelet/internal/repository"
|
"github.com/Rain-kl/Wavelet/internal/repository"
|
||||||
@@ -39,11 +39,11 @@ type CacheRegistry struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
registerTasksOnce sync.Once
|
registerTasksOnce sync.Once
|
||||||
registerPushDomainEventsOnce sync.Once
|
registerPushDomainEventsOnce sync.Once
|
||||||
registerTaskListenersOnce sync.Once
|
registerTaskListenersOnce sync.Once
|
||||||
registerMessageGatewayListenersOnce sync.Once
|
registerMessageGatewayListenersOnce sync.Once
|
||||||
initRuntimeOnce sync.Once
|
initRuntimeOnce sync.Once
|
||||||
|
|
||||||
cacheRegistries = make(map[string]CacheRegistry)
|
cacheRegistries = make(map[string]CacheRegistry)
|
||||||
cacheRegistriesMu sync.RWMutex
|
cacheRegistriesMu sync.RWMutex
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
configTypeSystem = "system"
|
configTypeSystem = "system"
|
||||||
configValueTrue = "true"
|
configTypeBusiness = "business"
|
||||||
configValueFalse = "false"
|
configValueTrue = "true"
|
||||||
|
configValueFalse = "false"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetupTestEnvironment initializes an in-memory SQLite DB, seeds default configurations,
|
// SetupTestEnvironment initializes an in-memory SQLite DB, seeds default configurations,
|
||||||
@@ -139,7 +140,7 @@ func getSeedConfigsPart1() []model.SystemConfig {
|
|||||||
{
|
{
|
||||||
Key: model.ConfigKeyMaxAPIKeysPerUser,
|
Key: model.ConfigKeyMaxAPIKeysPerUser,
|
||||||
Value: "5",
|
Value: "5",
|
||||||
Type: "business",
|
Type: configTypeBusiness,
|
||||||
Description: "限制每个普通用户可以创建的 API Key 最大数量",
|
Description: "限制每个普通用户可以创建的 API Key 最大数量",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -300,19 +301,19 @@ func getSeedConfigsPart2() []model.SystemConfig {
|
|||||||
{
|
{
|
||||||
Key: model.ConfigKeyLogRetentionDaysPostgres,
|
Key: model.ConfigKeyLogRetentionDaysPostgres,
|
||||||
Value: "30",
|
Value: "30",
|
||||||
Type: "business",
|
Type: configTypeBusiness,
|
||||||
Description: "PostgreSQL 用户访问日志保留天数",
|
Description: "PostgreSQL 用户访问日志保留天数",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: model.ConfigKeyLogRetentionDaysSQLite,
|
Key: model.ConfigKeyLogRetentionDaysSQLite,
|
||||||
Value: "30",
|
Value: "30",
|
||||||
Type: "business",
|
Type: configTypeBusiness,
|
||||||
Description: "SQLite 用户访问日志保留天数",
|
Description: "SQLite 用户访问日志保留天数",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: model.ConfigKeyLogRetentionDaysClickHouse,
|
Key: model.ConfigKeyLogRetentionDaysClickHouse,
|
||||||
Value: "30",
|
Value: "30",
|
||||||
Type: "business",
|
Type: configTypeBusiness,
|
||||||
Description: "ClickHouse 用户访问日志保留天数",
|
Description: "ClickHouse 用户访问日志保留天数",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright 2026 Arctel.net
|
// Copyright 2026 Arctel.net
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package qq implements the official QQ Bot C2C adapter.
|
||||||
package qq
|
package qq
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -69,10 +70,11 @@ func (a *Adapter) Connect(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var api openapi.OpenAPI
|
var api openapi.OpenAPI
|
||||||
|
const apiTimeout = 5 * time.Second
|
||||||
if strings.EqualFold(strings.TrimSpace(a.cfg.Extra["sandbox"]), "true") {
|
if strings.EqualFold(strings.TrimSpace(a.cfg.Extra["sandbox"]), "true") {
|
||||||
api = botgo.NewSandboxOpenAPI(credentials.AppID, tokSrc).WithTimeout(5 * time.Second)
|
api = botgo.NewSandboxOpenAPI(credentials.AppID, tokSrc).WithTimeout(apiTimeout)
|
||||||
} else {
|
} else {
|
||||||
api = botgo.NewOpenAPI(credentials.AppID, tokSrc).WithTimeout(5 * time.Second)
|
api = botgo.NewOpenAPI(credentials.AppID, tokSrc).WithTimeout(apiTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
wsAP, err := api.WS(ctx, nil, "")
|
wsAP, err := api.WS(ctx, nil, "")
|
||||||
@@ -92,7 +94,7 @@ func (a *Adapter) Connect(ctx context.Context) error {
|
|||||||
text = data.Content
|
text = data.Content
|
||||||
id = data.ID
|
id = data.ID
|
||||||
}
|
}
|
||||||
a.handleEvent(qqEvent{Kind: "c2c", UserID: authorID, Text: text, MessageID: id})
|
a.handleEvent(runCtx, qqEvent{Kind: "c2c", UserID: authorID, Text: text, MessageID: id})
|
||||||
return nil
|
return nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@@ -112,7 +114,7 @@ func (a *Adapter) Connect(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Disconnect stops token refresh and drops further inbound events.
|
// Disconnect stops token refresh and drops further inbound events.
|
||||||
func (a *Adapter) Disconnect(ctx context.Context) error {
|
func (a *Adapter) Disconnect(_ context.Context) error {
|
||||||
a.mu.Lock()
|
a.mu.Lock()
|
||||||
defer a.mu.Unlock()
|
defer a.mu.Unlock()
|
||||||
a.disconnected = true
|
a.disconnected = true
|
||||||
@@ -138,7 +140,7 @@ func (a *Adapter) Send(ctx context.Context, to message_gateway.Recipient, msg me
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adapter) handleEvent(ev qqEvent) {
|
func (a *Adapter) handleEvent(ctx context.Context, ev qqEvent) {
|
||||||
if ev.Kind != "c2c" {
|
if ev.Kind != "c2c" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -148,7 +150,7 @@ func (a *Adapter) handleEvent(ev qqEvent) {
|
|||||||
if disconnected || a.onInbound == nil {
|
if disconnected || a.onInbound == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = a.onInbound(context.Background(), message_gateway.InboundMessage{
|
_ = a.onInbound(ctx, message_gateway.InboundMessage{
|
||||||
ChannelID: a.cfg.ID,
|
ChannelID: a.cfg.ID,
|
||||||
ChannelType: message_gateway.ChannelTypeQQ,
|
ChannelType: message_gateway.ChannelTypeQQ,
|
||||||
PlatformUserID: ev.UserID,
|
PlatformUserID: ev.UserID,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ func TestHandleEvent_DropsNonC2C(t *testing.T) {
|
|||||||
got++
|
got++
|
||||||
return nil
|
return nil
|
||||||
}}
|
}}
|
||||||
a.handleEvent(qqEvent{Kind: "group", UserID: "u1", Text: "hi"})
|
a.handleEvent(context.Background(), qqEvent{Kind: "group", UserID: "u1", Text: "hi"})
|
||||||
if got != 0 {
|
if got != 0 {
|
||||||
t.Fatal("non-C2C must be ignored")
|
t.Fatal("non-C2C must be ignored")
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ func TestHandleEvent_C2CText(t *testing.T) {
|
|||||||
got = msg
|
got = msg
|
||||||
return nil
|
return nil
|
||||||
}}
|
}}
|
||||||
a.handleEvent(qqEvent{Kind: "c2c", UserID: "openid-1", Text: "hello", MessageID: "m1"})
|
a.handleEvent(context.Background(), qqEvent{Kind: "c2c", UserID: "openid-1", Text: "hello", MessageID: "m1"})
|
||||||
if got.Text != "hello" || got.PlatformUserID != "openid-1" || got.ChannelID != 3 {
|
if got.Text != "hello" || got.PlatformUserID != "openid-1" || got.ChannelID != 3 {
|
||||||
t.Fatalf("%+v", got)
|
t.Fatalf("%+v", got)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright 2026 Arctel.net
|
// Copyright 2026 Arctel.net
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package telegram implements the Telegram private-chat adapter.
|
||||||
package telegram
|
package telegram
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -53,15 +54,15 @@ func (a *Adapter) Connect(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
a.bot = bot
|
a.bot = bot
|
||||||
bot.Handle(tele.OnText, func(c tele.Context) error {
|
bot.Handle(tele.OnText, func(c tele.Context) error {
|
||||||
a.handleTeleMessage(c.Message())
|
a.handleTeleMessage(ctx, c.Message())
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
bot.Handle(tele.OnPhoto, func(c tele.Context) error {
|
bot.Handle(tele.OnPhoto, func(c tele.Context) error {
|
||||||
a.handleTeleMessage(c.Message())
|
a.handleTeleMessage(ctx, c.Message())
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
bot.Handle(tele.OnDocument, func(c tele.Context) error {
|
bot.Handle(tele.OnDocument, func(c tele.Context) error {
|
||||||
a.handleTeleMessage(c.Message())
|
a.handleTeleMessage(ctx, c.Message())
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
go bot.Start()
|
go bot.Start()
|
||||||
@@ -73,7 +74,7 @@ func (a *Adapter) Connect(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Disconnect stops the bot.
|
// Disconnect stops the bot.
|
||||||
func (a *Adapter) Disconnect(ctx context.Context) error {
|
func (a *Adapter) Disconnect(_ context.Context) error {
|
||||||
if a.bot != nil {
|
if a.bot != nil {
|
||||||
a.bot.Stop()
|
a.bot.Stop()
|
||||||
}
|
}
|
||||||
@@ -81,7 +82,7 @@ func (a *Adapter) Disconnect(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send replies to a private chat.
|
// Send replies to a private chat.
|
||||||
func (a *Adapter) Send(ctx context.Context, to message_gateway.Recipient, msg message_gateway.OutboundMessage) error {
|
func (a *Adapter) Send(_ context.Context, to message_gateway.Recipient, msg message_gateway.OutboundMessage) error {
|
||||||
if a.bot == nil {
|
if a.bot == nil {
|
||||||
return fmt.Errorf("telegram: not connected")
|
return fmt.Errorf("telegram: not connected")
|
||||||
}
|
}
|
||||||
@@ -93,7 +94,7 @@ func (a *Adapter) Send(ctx context.Context, to message_gateway.Recipient, msg me
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adapter) handleTeleMessage(m *tele.Message) {
|
func (a *Adapter) handleTeleMessage(ctx context.Context, m *tele.Message) {
|
||||||
if m == nil || m.Chat == nil || m.Chat.Type != tele.ChatPrivate {
|
if m == nil || m.Chat == nil || m.Chat.Type != tele.ChatPrivate {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -114,7 +115,7 @@ func (a *Adapter) handleTeleMessage(m *tele.Message) {
|
|||||||
if a.bot != nil {
|
if a.bot != nil {
|
||||||
msg.Attachments = a.downloadMedia(m)
|
msg.Attachments = a.downloadMedia(m)
|
||||||
}
|
}
|
||||||
_ = a.onInbound(context.Background(), msg)
|
_ = a.onInbound(ctx, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Adapter) downloadMedia(m *tele.Message) []message_gateway.Attachment {
|
func (a *Adapter) downloadMedia(m *tele.Message) []message_gateway.Attachment {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ func TestHandleUpdate_DropsGroups(t *testing.T) {
|
|||||||
got++
|
got++
|
||||||
return nil
|
return nil
|
||||||
}}
|
}}
|
||||||
a.handleTeleMessage(&tele.Message{
|
a.handleTeleMessage(context.Background(), &tele.Message{
|
||||||
ID: 1,
|
ID: 1,
|
||||||
Text: "hi",
|
Text: "hi",
|
||||||
Chat: &tele.Chat{ID: -100, Type: tele.ChatGroup},
|
Chat: &tele.Chat{ID: -100, Type: tele.ChatGroup},
|
||||||
@@ -37,7 +37,7 @@ func TestHandleUpdate_PrivateText(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
a.handleTeleMessage(&tele.Message{
|
a.handleTeleMessage(context.Background(), &tele.Message{
|
||||||
ID: 9,
|
ID: 9,
|
||||||
Text: "hi",
|
Text: "hi",
|
||||||
Chat: &tele.Chat{ID: 42, Type: tele.ChatPrivate},
|
Chat: &tele.Chat{ID: 42, Type: tele.ChatPrivate},
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright 2026 Arctel.net
|
// Copyright 2026 Arctel.net
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package message_gateway defines channel adapters, pairing codes, and inbound types.
|
||||||
package message_gateway
|
package message_gateway
|
||||||
|
|
||||||
// ChannelTypeTelegram is the Telegram private-chat adapter type.
|
// ChannelTypeTelegram is the Telegram private-chat adapter type.
|
||||||
|
|||||||
Reference in New Issue
Block a user