package puppy
import (
"errors"
"fmt"
)
// An interface that represents something that can be used to store data from the proxy
type MessageStorage interface {
// Close the storage
Close ( )
// Update an existing request in the storage. Requires that it has already been saved
UpdateRequest ( req * ProxyRequest ) error
// Save a new instance of the request in the storage regardless of if it has already been saved
SaveNewRequest ( req * ProxyRequest ) error
// Load a request given a unique id
LoadRequest ( reqid string ) ( * ProxyRequest , error )
// Load the unmangled version of a request given a unique id
LoadUnmangledRequest ( reqid string ) ( * ProxyRequest , error )
// Delete a request given a unique id
DeleteRequest ( reqid string ) error
// Update an existing response in the storage. Requires that it has already been saved
UpdateResponse ( rsp * ProxyResponse ) error
// Save a new instance of the response in the storage regardless of if it has already been saved
SaveNewResponse ( rsp * ProxyResponse ) error
// Load a response given a unique id
LoadResponse ( rspid string ) ( * ProxyResponse , error )
// Load the unmangled version of a response given a unique id
LoadUnmangledResponse ( rspid string ) ( * ProxyResponse , error )
// Delete a response given a unique id
DeleteResponse ( rspid string ) error
// Update an existing websocket message in the storage. Requires that it has already been saved
UpdateWSMessage ( req * ProxyRequest , wsm * ProxyWSMessage ) error
// Save a new instance of the websocket message in the storage regardless of if it has already been saved
SaveNewWSMessage ( req * ProxyRequest , wsm * ProxyWSMessage ) error
// Load a websocket message given a unique id
LoadWSMessage ( wsmid string ) ( * ProxyWSMessage , error )
// Load the unmangled version of a websocket message given a unique id
LoadUnmangledWSMessage ( wsmid string ) ( * ProxyWSMessage , error )
// Delete a websocket message given a unique id
DeleteWSMessage ( wsmid string ) error
// Get list of the keys for all of the stored requests
RequestKeys ( ) ( [ ] string , error )
// A function to perform a search of requests in the storage. Same arguments as NewRequestChecker
Search ( limit int64 , args ... interface { } ) ( [ ] * ProxyRequest , error )
// A function to naively check every function in storage with the given function and return the ones that match
CheckRequests ( limit int64 , checker RequestChecker ) ( [ ] * ProxyRequest , error )
// Return a list of all the queries stored in the MessageStorage
AllSavedQueries ( ) ( [ ] * SavedQuery , error )
// Save a query in the storage with a given name. If the name is already in storage, it should be overwritten
SaveQuery ( name string , query MessageQuery ) error
// Load a query by name from the storage
LoadQuery ( name string ) ( MessageQuery , error )
// Delete a query by name from the storage
DeleteQuery ( name string ) error
// Add a storage watcher to make callbacks to on message saves
Watch ( watcher StorageWatcher ) error
// Remove a storage watcher from the storage
EndWatch ( watcher StorageWatcher ) error
// Set/get plugin values
SetPluginValue ( key string , value string ) error
GetPluginValue ( key string ) ( string , error )
}
type StorageWatcher interface {
// Callback for when a new request is saved
NewRequestSaved ( ms MessageStorage , req * ProxyRequest )
// Callback for when a request is updated
RequestUpdated ( ms MessageStorage , req * ProxyRequest )
// Callback for when a request is deleted
RequestDeleted ( ms MessageStorage , DbId string )
// Callback for when a new response is saved
NewResponseSaved ( ms MessageStorage , rsp * ProxyResponse )
// Callback for when a response is updated
ResponseUpdated ( ms MessageStorage , rsp * ProxyResponse )
// Callback for when a response is deleted
ResponseDeleted ( ms MessageStorage , DbId string )
// Callback for when a new wsmessage is saved
NewWSMessageSaved ( ms MessageStorage , req * ProxyRequest , wsm * ProxyWSMessage )
// Callback for when a wsmessage is updated
WSMessageUpdated ( ms MessageStorage , req * ProxyRequest , wsm * ProxyWSMessage )
// Callback for when a wsmessage is deleted
WSMessageDeleted ( ms MessageStorage , DbId string )
}
// An error to be returned if a query is not supported
const QueryNotSupported = ConstErr ( "custom query not supported" )
// A type representing a search query that is stored in a MessageStorage
type SavedQuery struct {
Name string
Query MessageQuery
}
/ *
General storage functions
* /
// Save a new request and new versions of all its dependant messages (response, websocket messages, and unmangled versions of everything).
func SaveNewRequest ( ms MessageStorage , req * ProxyRequest ) error {
if req . ServerResponse != nil {
if err := SaveNewResponse ( ms , req . ServerResponse ) ; err != nil {
return fmt . Errorf ( "error saving server response to request: %s" , err . Error ( ) )
}
}
if req . Unmangled != nil {
if req . DbId != "" && req . DbId == req . Unmangled . DbId {
return errors . New ( "request has same DbId as unmangled version" )
}
if err := SaveNewRequest ( ms , req . Unmangled ) ; err != nil {
return fmt . Errorf ( "error saving unmangled version of request: %s" , err . Error ( ) )
}
}
if err := ms . SaveNewRequest ( req ) ; err != nil {
return fmt . Errorf ( "error saving new request: %s" , err . Error ( ) )
}
for _ , wsm := range req . WSMessages {
if err := SaveNewWSMessage ( ms , req , wsm ) ; err != nil {
return fmt . Errorf ( "error saving request's ws message: %s" , err . Error ( ) )
}
}
return nil
}
// Update a request and all its dependent messages. If the request has a DbId it will be updated, otherwise it will be inserted into the database and have its DbId updated. Same for all dependent messages
func UpdateRequest ( ms MessageStorage , req * ProxyRequest ) error {
if req . ServerResponse != nil {
if err := UpdateResponse ( ms , req . ServerResponse ) ; err != nil {
return fmt . Errorf ( "error saving server response to request: %s" , err . Error ( ) )
}
}
if req . Unmangled != nil {
if req . DbId != "" && req . DbId == req . Unmangled . DbId {
return errors . New ( "request has same DbId as unmangled version" )
}
if err := UpdateRequest ( ms , req . Unmangled ) ; err != nil {
return fmt . Errorf ( "error saving unmangled version of request: %s" , err . Error ( ) )
}
}
if req . DbId == "" {
if err := ms . SaveNewRequest ( req ) ; err != nil {
return fmt . Errorf ( "error saving new request: %s" , err . Error ( ) )
}
} else {
if err := ms . UpdateRequest ( req ) ; err != nil {
return fmt . Errorf ( "error updating request: %s" , err . Error ( ) )
}
}
for _ , wsm := range req . WSMessages {
if err := UpdateWSMessage ( ms , req , wsm ) ; err != nil {
return fmt . Errorf ( "error saving request's ws message: %s" , err . Error ( ) )
}
}
return nil
}
// Save a new response/unmangled response to the message storage regardless of the existence of a DbId
func SaveNewResponse ( ms MessageStorage , rsp * ProxyResponse ) error {
if rsp . Unmangled != nil {
if rsp . DbId != "" && rsp . DbId == rsp . Unmangled . DbId {
return errors . New ( "response has same DbId as unmangled version" )
}
if err := SaveNewResponse ( ms , rsp . Unmangled ) ; err != nil {
return fmt . Errorf ( "error saving unmangled version of response: %s" , err . Error ( ) )
}
}
return ms . SaveNewResponse ( rsp )
}
// Update a response and its unmangled version in the database. If it has a DbId, it will be updated, otherwise a new version will be saved in the database
func UpdateResponse ( ms MessageStorage , rsp * ProxyResponse ) error {
if rsp . Unmangled != nil {
if rsp . DbId != "" && rsp . DbId == rsp . Unmangled . DbId {
return errors . New ( "response has same DbId as unmangled version" )
}
if err := UpdateResponse ( ms , rsp . Unmangled ) ; err != nil {
return fmt . Errorf ( "error saving unmangled version of response: %s" , err . Error ( ) )
}
}
if rsp . DbId == "" {
return ms . SaveNewResponse ( rsp )
} else {
return ms . UpdateResponse ( rsp )
}
}
// Save a new websocket emssage/unmangled version to the message storage regardless of the existence of a DbId
func SaveNewWSMessage ( ms MessageStorage , req * ProxyRequest , wsm * ProxyWSMessage ) error {
if wsm . Unmangled != nil {
if wsm . DbId != "" && wsm . DbId == wsm . Unmangled . DbId {
return errors . New ( "websocket message has same DbId as unmangled version" )
}
if err := SaveNewWSMessage ( ms , nil , wsm . Unmangled ) ; err != nil {
return fmt . Errorf ( "error saving unmangled version of websocket message: %s" , err . Error ( ) )
}
}
return ms . SaveNewWSMessage ( req , wsm )
}
// Update a websocket message and its unmangled version in the database. If it has a DbId, it will be updated, otherwise a new version will be saved in the database
func UpdateWSMessage ( ms MessageStorage , req * ProxyRequest , wsm * ProxyWSMessage ) error {
if wsm . Unmangled != nil {
if wsm . DbId != "" && wsm . Unmangled . DbId == wsm . DbId {
return errors . New ( "websocket message has same DbId as unmangled version" )
}
if err := UpdateWSMessage ( ms , nil , wsm . Unmangled ) ; err != nil {
return fmt . Errorf ( "error saving unmangled version of websocket message: %s" , err . Error ( ) )
}
}
if wsm . DbId == "" {
return ms . SaveNewWSMessage ( req , wsm )
} else {
return ms . UpdateWSMessage ( req , wsm )
}
}