DEV Community

Cover image for Using Discord as your CDN.
Gabriel Grubba
Gabriel Grubba

Posted on

Using Discord as your CDN.

Gopher Discord

Sometimes you are an indie developer or just creating a prototype, and you can't afford to set up a bucket on S3. For those times, I created this straightforward API to solve the issue of saving images in a database.

You have to set up a bot, and the service will take care of the rest.

To save the images, you must send him a form post with the field file. The bot will save the photo and send it back as a URL so you can keep it in your database. In this blog post, I will explain what I've done and how you can set up for yourself this fantastic service.

Side note:
Thought that this post is not sponsored by Meteor Cloud. I recommend their service, and they have a free tier where you have a MongoDB instance that can be used to save that URL I mentioned above.

How to use it?

I will start linking the source code repo and ask you to give it a star.

If you want to run locally, you will need to set up a .env file with some info that the bot requires to work, and that is all. When you run the main function, it should create a web server where you can send a post request to it and store your photos dynamically. Again if you want a more detailed version of how to set up and run this service in your cloud infrastructure, you can check the source code repo. In this post, I will focus on how I did it.

How is it done?

As you can see in the source code, this is a Go code, so it is straightforward as it can be.

Creating HTTP server and Bot connection

In this first part of the main function, we have created the fiber HTTP server, and the creation of the /sendFile route. When this route is called, passing the file field, we have the creation of our discord bot using this excellent library called discordgo. We also open the WebSocket to talk to the Discord servers.

func main() {
    app := fiber.New()
    app.Use(cors.New())

    app.Post("/sendFile", func(ctx *fiber.Ctx) error {
        dg, err := discordgo.New("Bot " + os.Getenv("BOT_TOKEN"))

        if err != nil {
            fmt.Println("error creating Discord session,", err)
            return fiber.NewError(fiber.StatusBadRequest, "error creating Discord session")
        }

        err = dg.Open()
        if err != nil {
            fmt.Println("error opening connection,", err)
            return fiber.NewError(fiber.StatusBadRequest, "error opening connection,")

        }
Enter fullscreen mode Exit fullscreen mode

Getting the file and the channel

After creating the bot, we need to check if the file can be transformed into a stream. We do size and file type checking.


        file, err := ctx.FormFile("file")

        if err != nil {
            fmt.Println("Error getting file", err.Error())
            return fiber.NewError(fiber.StatusBadRequest, "Error getting file")
        }
        // do the checks and return a file to be sent to discord
        osFile, err := media.ToOSFile(ctx, file)
        if err != nil {
            fmt.Println("Error saving the file", err.Error())
            return fiber.NewError(fiber.StatusBadRequest, "Error saving the file")
        }


Enter fullscreen mode Exit fullscreen mode

Wrapping up and sending the URL

After doing all the necessary checks, we wrap the data into a struct that will be sent to discord and delivered to the bot. When sending the message is done, we gather the attachment URL and send it back to the user. We disconnect and clean up the server, so it is ready to receive another HTTP call.


data := &discordgo.MessageSend{
            Files: []*discordgo.File{
                {
                    Name:        file.Filename,
                    ContentType: file.Header.Get("Content-Type"),
                    Reader:      osFile,
                }},
        }

        msg, err := dg.ChannelMessageSendComplex(os.Getenv("CHANNEL_ID"), data)

        if err != nil {
            fmt.Println("Error sending the message ", err.Error())
            return fiber.NewError(fiber.StatusBadRequest, "Error sending the message")
        }

        r := new(Return)
        r.Url = msg.Attachments[0].URL

        // clean up and return
        if err := os.Remove(media.Path); err != nil {
            fmt.Println("Was not able to remove file", err.Error())
            return fiber.NewError(fiber.StatusBadRequest, "Was not able to remove file")
        }

        defer func(dg *discordgo.Session) {
            err := dg.Close()
            if err != nil {
                fmt.Println(err)
            }
        }(dg)
        return ctx.JSON(r)

    log.Fatal(app.Listen(":" + os.Getenv("PORT")))
}

Enter fullscreen mode Exit fullscreen mode

Conclusion

With less than 100 lines, you can set up a bot a discord bot and make it do extraordinary things for you. I hope that this blog post is helpful to you in any way!

If you did like this content, please follow me on GitHub and Twitter for more! Also, liking this post will help me a lot. See you soon!

Top comments (2)

Collapse
 
songyang-dev profile image
Song Yang

How stable is the discord CDN? How long do things live on the CDN?

Collapse
 
elhallo168550 profile image
Elhallo

pretty stable, for ever