@@ -4,9 +4,12 @@ import (
44 "context"
55 "flag"
66 "fmt"
7+ "io"
78 "log"
9+ "net/http"
810 "os"
911 "os/signal"
12+ "path/filepath"
1013 "regexp"
1114 "strings"
1215
2528 pclient * piston.Client
2629)
2730
31+ const (
32+ cblock int = iota
33+ cgist
34+ cfile
35+ )
36+
2837// code execution ouptput
2938var o chan string
3039
@@ -72,29 +81,35 @@ func executionHandler(s *discordgo.Session, m *discordgo.MessageCreate) {
7281
7382 // extract code block from message and execute code
7483 var responseContent string
75- if lang , codeBlock := codeBlockExtractor (m .Content ); lang != "" || codeBlock != "" {
84+ ctype , lang , codeBlock := codeBlockExtractor (m .Message )
85+ if lang != "" || codeBlock != "" {
7686 go exec (m .ChannelID , codeBlock , m .Reference (), lang )
7787 responseContent = <- o
7888 } else {
7989 return
8090 }
8191
82- // send initial reply message containing output of code execution
83- // "Run" button is injected in the message so the user may re run their code
84- _ , _ = s .ChannelMessageSendComplex (m .ChannelID , & discordgo.MessageSend {
85- Content : responseContent ,
86- Reference : m .Reference (),
87- Components : []discordgo.MessageComponent {
88- discordgo.ActionsRow {
89- Components : []discordgo.MessageComponent {
90- discordgo.Button {
91- Label : "Run" ,
92- Style : discordgo .SuccessButton ,
93- CustomID : "run" ,
94- },
92+ // only add run button for code block and gist execution
93+ var runButton []discordgo.MessageComponent
94+ if ctype != cfile {
95+ runButton = []discordgo.MessageComponent {discordgo.ActionsRow {
96+ Components : []discordgo.MessageComponent {
97+ discordgo.Button {
98+ Label : "Run" ,
99+ Style : discordgo .SuccessButton ,
100+ CustomID : "run" ,
95101 },
96102 },
97103 },
104+ }
105+ }
106+
107+ // send initial reply message containing output of code execution
108+ // "Run" button is injected in the message so the user may re run their code
109+ _ , _ = s .ChannelMessageSendComplex (m .ChannelID , & discordgo.MessageSend {
110+ Content : responseContent ,
111+ Reference : m .Reference (),
112+ Components : runButton ,
98113 })
99114}
100115
@@ -111,7 +126,7 @@ func reExecuctionHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
111126
112127 // extract code block from message and execute code
113128 var responseContent string
114- if lang , codeBlock := codeBlockExtractor (m . Content ); lang != "" || codeBlock != "" {
129+ if _ , lang , codeBlock := codeBlockExtractor (m ); lang != "" || codeBlock != "" {
115130 go exec (i .ChannelID , codeBlock , i .Message .Reference (), lang )
116131 responseContent = <- o
117132 } else {
@@ -157,46 +172,72 @@ func exec(channelID string, code string, messageReference *discordgo.MessageRefe
157172 },
158173 )
159174 if err != nil {
160- fmt .Println (err .Error ())
161- _ , _ = s .ChannelMessageSendReply (channelID , err .Error (), messageReference )
175+ o <- fmt .Sprintf (">>> Execution Failed [%s - %s]\n ```\n %s\n ```\n " , output .Language , output .Version , err )
162176 }
163177
164178 o <- fmt .Sprintf (">>> Output [%s - %s]\n ```\n %s\n ```\n " , output .Language , output .Version , output .GetOutput ())
165179}
166180
167- func codeBlockExtractor (content string ) (string , string ) {
168- // check to see if we are executing a code block
181+ func codeBlockExtractor (m * discordgo.Message ) (int , string , string ) {
182+ mc := m .Content
183+ // syntax for executing a code block
169184 // this is based on a writing standard in discord for writing code in a paragraph message block
170185 // example message: ```go ... ```
171186 rcb , _ := regexp .Compile ("run```.*" )
187+ // syntax for executing a gist
172188 rg , _ := regexp .Compile ("run https://gist.github.com/.*/.*" )
173189 rgist , _ := regexp .Compile ("run https://gist.github.com/.*/" )
174- c := strings .Split (content , "\n " )
175- for bi , bb := range c {
176- // extract gist language and code to execute
177- if rg .MatchString (bb ) {
178- gistID := rgist .ReplaceAllString (bb , "" )
179- gist , _ , _ := gclient .Gists .Get (ctx , gistID )
180- return strings .ToLower (* gist .Files ["helloworld.go" ].Language ), * gist .Files ["helloworld.go" ].Content
181- }
190+ // syntax for executing an attached file
191+ rf , _ := regexp .Compile ("run *.*" )
182192
193+ c := strings .Split (mc , "\n " )
194+ for bi , bb := range c {
183195 // extract code block to execute
184196 if rcb .MatchString (bb ) {
185- lang := strings .TrimPrefix (string (rcb .Find ([]byte (content ))), "run```" )
197+ lang := strings .TrimPrefix (string (rcb .Find ([]byte (mc ))), "run```" )
186198 // find end of code block
187199 var codeBlock string
188200 endBlockRegx , _ := regexp .Compile ("```" )
189- subArray := c [bi + 1 :]
190201
191- for ei , eb := range subArray {
202+ sa := c [bi + 1 :]
203+ for ei , eb := range sa {
192204 if endBlockRegx .Match ([]byte (eb )) {
193205 // create code block to execute
194- codeBlock = strings .Join (subArray [:ei ], "\n " )
195- return lang , codeBlock
206+ codeBlock = strings .Join (sa [:ei ], "\n " )
207+ return cblock , lang , codeBlock
208+ }
209+ }
210+ }
211+ // extract gist language and code to execute
212+ if rg .MatchString (bb ) {
213+ gistID := rgist .ReplaceAllString (bb , "" )
214+ gist , _ , err := gclient .Gists .Get (ctx , gistID )
215+ if err != nil {
216+ log .Printf ("Failed to obtain gist: %v\n " , err )
217+ }
218+ return cgist , strings .ToLower (* gist .Files ["helloworld.go" ].Language ), * gist .Files ["helloworld.go" ].Content
219+ }
220+ // extract file language and code to execute
221+ if rf .MatchString (bb ) {
222+ if len (m .Attachments ) > 0 {
223+ // handle 1 file in message attachments
224+ f := m .Attachments [0 ]
225+ // get language from extension
226+ lang := strings .TrimLeft (filepath .Ext (f .Filename ), "." )
227+ // get code from file
228+ resp , err := http .Get (f .URL )
229+ if err != nil {
230+ log .Printf ("Failed GET http call to file attachment URL: %v\n " , err )
231+ }
232+ defer resp .Body .Close ()
233+ codeBlock , err := io .ReadAll (resp .Body )
234+ if err != nil {
235+ log .Printf ("Failed to obtain code from response body: %v\n " , err )
196236 }
237+ return cfile , lang , string (codeBlock )
197238 }
198239 }
199240 }
200241
201- return "" , ""
242+ return - 1 , "" , ""
202243}
0 commit comments