Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
P
pyfed
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
funkwhale
pyfed
Commits
e223eaad
Commit
e223eaad
authored
5 months ago
by
supersonicwisd1
Browse files
Options
Downloads
Patches
Plain Diff
added send_message to example
Signed-off-by: supersonicwisd1 <supersonicwisd1>
parent
2de0b395
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
examples/send_message.py
+148
-0
148 additions, 0 deletions
examples/send_message.py
with
148 additions
and
0 deletions
examples/send_message.py
0 → 100644
+
148
−
0
View file @
e223eaad
"""
Example of sending a message to Mastodon following ActivityPub spec.
"""
import
asyncio
import
logging
from
pathlib
import
Path
import
sys
from
config
import
CONFIG
from
datetime
import
datetime
,
timezone
# Add src directory to Python path
src_path
=
Path
(
__file__
).
parent
.
parent
/
"
src
"
sys
.
path
.
insert
(
0
,
str
(
src_path
))
from
pyfed.models
import
APPerson
,
APNote
,
APCreate
from
pyfed.federation.delivery
import
ActivityDelivery
from
pyfed.federation.discovery
import
InstanceDiscovery
from
pyfed.security.key_management
import
KeyManager
logging
.
basicConfig
(
level
=
logging
.
DEBUG
)
# Set to DEBUG for more detailed logs
logger
=
logging
.
getLogger
(
__name__
)
# @gvelez17@mas.to
async
def
send_activity_to_mastodon
():
# Initialize components with config
key_manager
=
KeyManager
(
domain
=
CONFIG
[
"
domain
"
],
keys_path
=
CONFIG
[
"
keys_path
"
],
rotation_config
=
False
)
await
key_manager
.
initialize
()
# Force generate a new key with proper format
# await key_manager.rotate_keys()
active_key
=
await
key_manager
.
get_active_key
()
logger
.
debug
(
f
"
Using active key ID:
{
active_key
.
key_id
}
"
)
logger
.
debug
(
f
"
Key document URL: https://
{
CONFIG
[
'
domain
'
]
}
/keys/
{
active_key
.
key_id
.
split
(
'
/
'
)[
-
1
]
}
"
)
discovery
=
InstanceDiscovery
()
await
discovery
.
initialize
()
delivery
=
ActivityDelivery
(
key_manager
=
key_manager
,
discovery
=
discovery
)
try
:
# 1. First, perform WebFinger lookup to get the actor's URL
logger
.
info
(
"
Performing WebFinger lookup...
"
)
webfinger_result
=
await
discovery
.
webfinger
(
resource
=
"
acct:kene29@mastodon.social
"
)
logger
.
info
(
f
"
WebFinger result:
{
webfinger_result
}
"
)
if
not
webfinger_result
:
raise
Exception
(
"
Could not find user through WebFinger
"
)
# Find ActivityPub actor URL from WebFinger result
actor_url
=
None
for
link
in
webfinger_result
.
get
(
'
links
'
,
[]):
if
link
.
get
(
'
rel
'
)
==
'
self
'
and
link
.
get
(
'
type
'
)
==
'
application/activity+json
'
:
actor_url
=
link
.
get
(
'
href
'
)
break
if
not
actor_url
:
raise
Exception
(
"
Could not find ActivityPub actor URL
"
)
# 2. Fetch the actor's profile to get their inbox URL
logger
.
info
(
f
"
Fetching actor profile from
{
actor_url
}
"
)
async
with
discovery
.
session
.
get
(
actor_url
)
as
response
:
if
response
.
status
!=
200
:
raise
Exception
(
f
"
Failed to fetch actor profile:
{
response
.
status
}
"
)
actor_data
=
await
response
.
json
()
# Get the inbox URL from the actor's profile
inbox_url
=
actor_data
.
get
(
'
inbox
'
)
if
not
inbox_url
:
raise
Exception
(
"
Could not find actor
'
s inbox URL
"
)
logger
.
info
(
f
"
Found actor
'
s inbox:
{
inbox_url
}
"
)
# 3. Create the Activity with ngrok domain
note_id
=
f
"
https://
{
CONFIG
[
'
domain
'
]
}
/notes/
{
int
(
asyncio
.
get_event_loop
().
time
()
*
1000
)
}
"
# Create actor
actor
=
APPerson
(
id
=
f
"
https://
{
CONFIG
[
'
domain
'
]
}
/users/
{
CONFIG
[
'
user
'
]
}
"
,
name
=
"
Alice
"
,
preferred_username
=
"
alice
"
,
inbox
=
"
https://example.com/users/alice/inbox
"
,
outbox
=
"
https://example.com/users/alice/outbox
"
,
followers
=
"
https://example.com/users/alice/followers
"
)
# Create note with string attributed_to
note
=
APNote
(
id
=
note_id
,
content
=
f
"
Hello @gvelez17@mas.to! This is a test note to test mention to Golda
"
,
attributed_to
=
str
(
actor
.
id
),
# Convert URL to string
to
=
[
inbox_url
],
cc
=
[
"
https://www.w3.org/ns/activitystreams#Public
"
],
published
=
datetime
.
utcnow
().
isoformat
()
+
"
Z
"
,
url
=
str
(
note_id
),
tag
=
[{
"
type
"
:
"
Mention
"
,
"
href
"
:
actor_url
,
"
name
"
:
"
@gvelez17@mas.to
"
}]
)
# Create activity
create_activity
=
APCreate
(
id
=
f
"
https://example.com/activities/
{
datetime
.
now
(
timezone
.
utc
).
timestamp
()
}
"
,
actor
=
str
(
actor
.
id
),
# Convert URL to string
object
=
note
,
to
=
note
.
to
,
cc
=
note
.
cc
,
published
=
datetime
.
utcnow
().
isoformat
()
+
"
Z
"
,
)
# 4. Deliver the activity
logger
.
info
(
"
Delivering activity...
"
)
result
=
await
delivery
.
deliver_to_inbox
(
activity
=
create_activity
.
serialize
(),
inbox_url
=
inbox_url
,
username
=
CONFIG
[
"
user
"
]
)
logger
.
info
(
f
"
Delivery result:
{
result
}
"
)
if
result
.
success
:
logger
.
info
(
"
Activity delivered successfully!
"
)
logger
.
info
(
f
"
Successfully delivered to:
{
result
.
success
}
"
)
else
:
logger
.
error
(
"
Activity delivery failed!
"
)
if
result
.
failed
:
logger
.
error
(
f
"
Failed recipients:
{
result
.
failed
}
"
)
if
result
.
error_message
:
logger
.
error
(
f
"
Error:
{
result
.
error_message
}
"
)
except
Exception
as
e
:
logger
.
error
(
f
"
Error:
{
e
}
"
)
finally
:
# Clean up
await
discovery
.
close
()
await
delivery
.
close
()
if
__name__
==
"
__main__
"
:
asyncio
.
run
(
send_activity_to_mastodon
())
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment