Skip to content

Instantly share code, notes, and snippets.

@ross-spencer
Created November 27, 2019 14:59
Show Gist options
  • Save ross-spencer/1a94d90249e7c96cc4ec48bb7bfdc002 to your computer and use it in GitHub Desktop.
Save ross-spencer/1a94d90249e7c96cc4ec48bb7bfdc002 to your computer and use it in GitHub Desktop.
Test Archivematica callbacks
// Basic server capability to test storage service callbacks.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
)
func main() {
http.HandleFunc("/", CallbackServer)
http.HandleFunc("/package/*", CallbackServer)
http.ListenAndServe(":8080", nil)
}
// CallbackMessage allows us to parse JSON into a struct to use within code.
type CallbackMessage struct {
PackageID string
PackageName string
}
// CallbackServer handles the incoming POST request via the storage service callback.
func CallbackServer(w http.ResponseWriter, r *http.Request) {
log.Printf("%s", formatRequest(r))
switch r.Method {
case "GET":
case "POST":
if err := r.ParseForm(); err != nil {
fmt.Fprintf(w, "ParseForm() err: %v", err)
return
}
fmt.Fprintf(w, "Post from callback! r.PostFrom = %v\n", r.PostForm)
fmt.Fprintf(w, "Headers: %v\n", r.Header)
decoder := json.NewDecoder(r.Body)
var aip CallbackMessage
err := decoder.Decode(&aip)
if err != nil {
panic(err)
}
fmt.Printf("Package ID: %s, Package Name: %s", aip.PackageID, aip.PackageName)
default:
fmt.Fprintf(w, "Sorry, only GET and POST methods are supported.")
}
}
// formatRequest generates an ascii representation of a request.
func formatRequest(r *http.Request) string {
// Create return string
var request []string
// Add the request string
url := fmt.Sprintf("%v %v %v", r.Method, r.URL, r.Proto)
request = append(request, url)
// Add the host
request = append(request, fmt.Sprintf("Host: %v", r.Host))
// Loop through headers
for name, headers := range r.Header {
name = strings.ToLower(name)
for _, h := range headers {
request = append(request, fmt.Sprintf("%v: %v", name, h))
}
}
// If this is a POST, add post data
if r.Method == "POST" {
r.ParseForm()
request = append(request, "\n")
request = append(request, r.Form.Encode())
}
// Return the request as a string
return strings.Join(request, "\n")
}
@ross-spencer
Copy link
Author

Testing callbacks from the Storage Service

image

The callback will place <package_name> into the URL to test its appearance there. It will also return JSON which is formatted to include the new <package_name> and <package_uuid> which tests the new and old capability. The code above (instructions below) will parse this JSON and return it in a sensible way to the user.

  1. Create the callback as per the image above.
  2. Download the code above, and run go build. The lowest path of resistance is to do this on localhost where the storage service also is, and it will listen on port 8080.

When an AIP is created a result such as follows will be returned:

2019/11/27 15:11:52 POST /package/20123_New_transfer_002.001.124 HTTP/1.1
Host: 127.0.0.1:8080
user-agent: python-requests/2.21.0
content-type: application/json
content-length: 109
connection: keep-alive
accept-encoding: gzip, deflate
accept: */*


Package ID: fd6a3f60-1431-4ca2-b146-ca2a57f438c9, Package Name: 20123_New_transfer_002.001.124

Of note:

  1. 2019/11/27 15:11:52 POST /package/20123_New_transfer_002.001.124 HTTP/1.1 is a URL constructed in the storage service which now contains the package name.
  2. Package ID: fd6a3f60-1431-4ca2-b146-ca2a57f438c9, Package Name: 20123_New_transfer_002.001.124 are both values replaced by the callback function in the storage service and reflect what we're expecting from the service.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment