-
Notifications
You must be signed in to change notification settings - Fork 366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modularize #20
Comments
Hi Jordan! Thanks for offering your help - and welcome to the project! |
Hey, thanks for the quick reply! I wrote up a draft of what the public API could look like. Would love to get some feedback/suggestions. Guerrilla// Returns a new instance of Guerrilla with the given config, not yet running.
func New(*Config, Backend) Guerrilla
// Main app object. Can contain multiple servers, and one backend.
// Can delegate things like configuration changes and global events to servers,
// and aggregate info from servers for the web analytics panel down the road
type Guerrilla interface {
// Starts the app, and all servers in the config.
// Equivalent to running `guerrillad serve`
Run()
// Resets the app's configuration and restarts each server
Reload(*Config)
} Server// Returns a new server instance with the given config, not yet running.
// Sets up TLS etc.
func NewServer(*ServerConfig) Server
type Server interface {
// Starts the server
Run()
// Hot reloads a new configuration
Reload(*ServerConfig)
} Client// Symbolic constant representing client's state
type ClientState int
type Client struct {
State ClientState
Helo string
MailFrom *EmailParts
RcptTo []*EmailParts
Data string
ConnectedAt time.Time
KilledAt time.Time
SavedNotify chan int
ID int64
// other fields unexported
}
// Notify client whether save operation succeeded or failed
func (c *Client) Notify(saved bool) Backend// Where all received mail is sent. Consumers of the `guerrilla` package would implement `Backend`
// as they see fit (send to RabbitMQ / store in Mongo) or use the built in SQL+Redis backend
// implementation. Then would pass any Backend to `guerrilla.New` when creating an app instance.
type Backend interface {
// Processes and stores data from a client, notifies success/failure over client's channel when complete.
Process(*Client)
} Config// Config that applies globally to a `guerrilla.Guerrilla` object,
// which may contain multiple `guerrilla.Server`s
type Config struct {
Servers []*ServerConfig
AllowedHosts []string
}
// Config for one server.
type ServerConfig struct {
IsEnabled bool
Hostname string
AllowedHosts []string
MaxSize int64
PrivateKeyFile string
PublicKeyFile string
Timeout int
ListenInterface string
AdvertiseTLS bool
RequireTLS bool
MaxClients int
} In order to do this, I think it would be a good idea to:
I've done a code review and have made a number of changes on my fork:
It would probably be easiest to incorporate these and get them checked by you guys in the same PR as the API. Would love to get some feedback on all this. Cheers! Edit: Could you elaborate a bit on the issue of saving emails in chunks? |
Thanks for the proposal! Just got back from travelling and getting ready to merge in #19 (been working on it while on the road) About collapsing, didn't realize that the current package layout has these impacts. Will the API be abstracted from the internal working of the server? For example, the API callee might not want to know about Would an alternative way to do this would be to create a new guerrilla/api package, and then the api package wraps/imports everything it needs, then the consumer would only need to import guerrilla/api package? Also, in case there is a circular dependency (ouch!), would it be valid just to break up rather combining all into one? To elaborate on saving email in chunks: The DATA command can buffer a lot of data to memory, so it would be good to save this data out of memory as it's being received. For example, on every 1MB read (or some other boundary), the data chunk could be passed to the backend, saved and then the memory can be freed/recycled (circular buffer perhaps?). Still haven't figured out how to implement this yet, but it would be something that would allow the server to support larger attachments. |
My thought on the API is: type CustomBackend struct {...}
func (c *CustomBackend) Process(c *guerrila.Client) {
// Do what you need with the received message
}
backend := &CustomBackend{}
config := readConfigFromFile()
myApp := guerrila.New(backend, config)
myApp.Start() Moving the api to its own package might be a good solution too. I'll try that out and we can see how it looks. |
Hi, I'm currently working on a project that will require an SMTP server with API hooks for processing received mail, and it sounds like you'd like this project to support that, given the
Modularize
bounty.I would be interested in doing a code review and implementing a public API for the package, if that's still something you are interested in adding.
The text was updated successfully, but these errors were encountered: