mirror of
https://github.com/diamondburned/cchat.git
synced 2024-10-31 20:04:33 +00:00
Added AuthenticateError
This commit broke both the cchat API and its repository generation API to accomodate for custom error types, as the new Authenticator API now uses AuthenticateError over error to add in multi-stage authentication instead of the old method with the for loop. This commit also removed the multistage example documented in Authenticator, as the API is now clearer. This commit also added the WrapAuthenticateError helper function that wraps a normal error into an AuthenticateError that does not have a NextStage return. Backends should use this for
This commit is contained in:
parent
c32c50c0e8
commit
955b99c9b6
45
cchat.go
45
cchat.go
|
@ -180,31 +180,34 @@ type Attachments interface {
|
||||||
Attachments() []MessageAttachment
|
Attachments() []MessageAttachment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthenticateError is the error returned when authenticating. This error
|
||||||
|
// interface extends the normal error to allow backends to implement multi-stage
|
||||||
|
// authentication if needed in a clean way without needing any loops.
|
||||||
|
//
|
||||||
|
// This interface satisfies the error interface.
|
||||||
|
type AuthenticateError interface {
|
||||||
|
// NextStage optionally returns a slice of Authenticator interfaces if the
|
||||||
|
// authentication process requires another stage. It works similarly to
|
||||||
|
// Service's Authenticate method, both of which returns a slice of
|
||||||
|
// Authenticators.
|
||||||
|
//
|
||||||
|
// If the error returned is an actual error, and that the user should retry any
|
||||||
|
// of the authentication fields, then NextStage could return nil to signify the
|
||||||
|
// error. The frontend could reliably check nil on this field to determine
|
||||||
|
// whether or not it should recreate the authentication fields.
|
||||||
|
NextStage() []Authenticator
|
||||||
|
// Error returns the error as a string. This method makes AuthenticateError
|
||||||
|
// satisfy the built-in error interface.
|
||||||
|
Error() string
|
||||||
|
}
|
||||||
|
|
||||||
// The authenticator interface allows for a multistage initial authentication
|
// The authenticator interface allows for a multistage initial authentication
|
||||||
// API that the backend could use. Multistage is done by calling
|
// API that the backend could use. Multistage is done by calling Authenticate
|
||||||
// AuthenticateForm then Authenticate again forever until no errors are
|
// and check for AuthenticateError's NextStage method.
|
||||||
// returned.
|
|
||||||
//
|
|
||||||
// var s *cchat.Session
|
|
||||||
// var err error
|
|
||||||
//
|
|
||||||
// for {
|
|
||||||
// // Pseudo-function to render the form and return the results of those
|
|
||||||
// // forms when the user confirms it.
|
|
||||||
// outputs := renderAuthForm(svc.AuthenticateForm())
|
|
||||||
//
|
|
||||||
// s, err = svc.Authenticate(outputs)
|
|
||||||
// if err != nil {
|
|
||||||
// renderError(errors.Wrap(err, "Error while authenticating"))
|
|
||||||
// continue // retry
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// break // success
|
|
||||||
// }
|
|
||||||
type Authenticator interface {
|
type Authenticator interface {
|
||||||
// Authenticate will be called with a list of values with indices correspond to
|
// Authenticate will be called with a list of values with indices correspond to
|
||||||
// the returned slice of AuthenticateEntry.
|
// the returned slice of AuthenticateEntry.
|
||||||
Authenticate([]string) (Session, error) // Blocking
|
Authenticate([]string) (Session, AuthenticateError) // Blocking
|
||||||
// AuthenticateForm should return a list of authentication entries for the
|
// AuthenticateForm should return a list of authentication entries for the
|
||||||
// frontend to render.
|
// frontend to render.
|
||||||
AuthenticateForm() []AuthenticateEntry
|
AuthenticateForm() []AuthenticateEntry
|
||||||
|
|
|
@ -62,13 +62,13 @@ func generateInterfaces(ifaces []repository.Interface) jen.Code {
|
||||||
|
|
||||||
switch method := method.(type) {
|
switch method := method.(type) {
|
||||||
case repository.GetterMethod:
|
case repository.GetterMethod:
|
||||||
stmt.Params(generateFuncParams(method.Parameters, false)...)
|
stmt.Params(generateFuncParams(method.Parameters, "")...)
|
||||||
stmt.Params(generateFuncParams(method.Returns, method.ReturnError)...)
|
stmt.Params(generateFuncParams(method.Returns, method.ErrorType)...)
|
||||||
case repository.SetterMethod:
|
case repository.SetterMethod:
|
||||||
stmt.Params(generateFuncParams(method.Parameters, false)...)
|
stmt.Params(generateFuncParams(method.Parameters, "")...)
|
||||||
case repository.IOMethod:
|
case repository.IOMethod:
|
||||||
stmt.Params(generateFuncParams(method.Parameters, false)...)
|
stmt.Params(generateFuncParams(method.Parameters, "")...)
|
||||||
stmt.Params(generateFuncParamErr(method.ReturnValue, method.ReturnError)...)
|
stmt.Params(generateFuncParamErr(method.ReturnValue, method.ErrorType)...)
|
||||||
stmt.Comment("// Blocking")
|
stmt.Comment("// Blocking")
|
||||||
case repository.ContainerMethod:
|
case repository.ContainerMethod:
|
||||||
stmt.Params(generateContainerFuncParams(method)...)
|
stmt.Params(generateContainerFuncParams(method)...)
|
||||||
|
@ -92,18 +92,18 @@ func generateInterfaces(ifaces []repository.Interface) jen.Code {
|
||||||
return stmt
|
return stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateFuncParamErr(param repository.NamedType, genErr bool) []jen.Code {
|
func generateFuncParamErr(param repository.NamedType, errorType string) []jen.Code {
|
||||||
stmt := make([]jen.Code, 0, 2)
|
stmt := make([]jen.Code, 0, 2)
|
||||||
|
|
||||||
if !param.IsZero() {
|
if !param.IsZero() {
|
||||||
stmt = append(stmt, generateFuncParam(param))
|
stmt = append(stmt, generateFuncParam(param))
|
||||||
}
|
}
|
||||||
|
|
||||||
if genErr {
|
if errorType != "" {
|
||||||
if param.Name == "" {
|
if param.Name == "" {
|
||||||
stmt = append(stmt, jen.Error())
|
stmt = append(stmt, jen.Id(errorType))
|
||||||
} else {
|
} else {
|
||||||
stmt = append(stmt, jen.Err().Error())
|
stmt = append(stmt, jen.Err().Id(errorType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ func generateFuncParam(param repository.NamedType) jen.Code {
|
||||||
return jen.Id(param.Name).Add(genutils.GenerateType(param))
|
return jen.Id(param.Name).Add(genutils.GenerateType(param))
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateFuncParams(params []repository.NamedType, withError bool) []jen.Code {
|
func generateFuncParams(params []repository.NamedType, errorType string) []jen.Code {
|
||||||
if len(params) == 0 {
|
if len(params) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -127,11 +127,11 @@ func generateFuncParams(params []repository.NamedType, withError bool) []jen.Cod
|
||||||
stmt.Add(generateFuncParam(param))
|
stmt.Add(generateFuncParam(param))
|
||||||
}
|
}
|
||||||
|
|
||||||
if withError {
|
if errorType != "" {
|
||||||
if params[0].Name != "" {
|
if params[0].Name != "" {
|
||||||
stmt.Add(jen.Err().Error())
|
stmt.Add(jen.Err().Id(errorType))
|
||||||
} else {
|
} else {
|
||||||
stmt.Add(jen.Error())
|
stmt.Add(jen.Id(errorType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
24
cmd/internal/cchat-gob-gen/main.go
Normal file
24
cmd/internal/cchat-gob-gen/main.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/gob"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/diamondburned/cchat/repository"
|
||||||
|
)
|
||||||
|
|
||||||
|
const output = "repository.gob"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
f, err := os.Create(output)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Failed to create file:", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
if err := gob.NewEncoder(f).Encode(repository.Main); err != nil {
|
||||||
|
os.Remove(output)
|
||||||
|
log.Fatalln("Failed to gob encode:", err)
|
||||||
|
}
|
||||||
|
}
|
14
generator.go
14
generator.go
|
@ -1,3 +1,17 @@
|
||||||
package cchat
|
package cchat
|
||||||
|
|
||||||
//go:generate go run ./cmd/internal/cchat-generator
|
//go:generate go run ./cmd/internal/cchat-generator
|
||||||
|
|
||||||
|
type authenticateError struct{ error }
|
||||||
|
|
||||||
|
func (authenticateError) NextStage() []Authenticator { return nil }
|
||||||
|
|
||||||
|
// WrapAuthenticateError wraps the given error to become an AuthenticateError.
|
||||||
|
// Its NextStage method returns nil. If the given err is nil, then nil is
|
||||||
|
// returned.
|
||||||
|
func WrapAuthenticateError(err error) AuthenticateError {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return authenticateError{err}
|
||||||
|
}
|
||||||
|
|
|
@ -56,7 +56,10 @@ func (c Comment) WrapText(column int) string {
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
doc.ToText(&buf, txt, "", strings.Repeat(" ", TabWidth-1), column)
|
doc.ToText(&buf, txt, "", strings.Repeat(" ", TabWidth-1), column)
|
||||||
|
|
||||||
return strings.TrimRight(buf.String(), "\n")
|
text := strings.TrimRight(buf.String(), "\n")
|
||||||
|
text = strings.Replace(text, "\t", strings.Repeat(" ", TabWidth), -1)
|
||||||
|
|
||||||
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unindent removes the indentations that were there for the sake of syntax in
|
// Unindent removes the indentations that were there for the sake of syntax in
|
||||||
|
|
|
@ -6,36 +6,40 @@ import (
|
||||||
"github.com/go-test/deep"
|
"github.com/go-test/deep"
|
||||||
)
|
)
|
||||||
|
|
||||||
const _comment = `
|
const _goComment = `
|
||||||
The authenticator interface allows for a multistage initial authentication API
|
// The authenticator interface allows for a multistage initial authentication
|
||||||
that the backend could use. Multistage is done by calling AuthenticateForm then
|
// API that the backend could use. Multistage is done by calling
|
||||||
Authenticate again forever until no errors are returned.
|
// AuthenticateForm then Authenticate again forever until no errors are
|
||||||
|
// returned.
|
||||||
var s *cchat.Session
|
//
|
||||||
var err error
|
// var s *cchat.Session
|
||||||
|
// var err error
|
||||||
for {
|
//
|
||||||
// Pseudo-function to render the form and return the results of those
|
// for {
|
||||||
// forms when the user confirms it.
|
// // Pseudo-function to render the form and return the results of those
|
||||||
outputs := renderAuthForm(svc.AuthenticateForm())
|
// // forms when the user confirms it.
|
||||||
|
// outputs := renderAuthForm(svc.AuthenticateForm())
|
||||||
s, err = svc.Authenticate(outputs)
|
//
|
||||||
if err != nil {
|
// s, err = svc.Authenticate(outputs)
|
||||||
renderError(errors.Wrap(err, "Error while authenticating"))
|
// if err != nil {
|
||||||
continue // retry
|
// renderError(errors.Wrap(err, "Error while authenticating"))
|
||||||
}
|
// continue // retry
|
||||||
|
// }
|
||||||
break // success
|
//
|
||||||
}`
|
// break // success
|
||||||
|
// }`
|
||||||
|
|
||||||
// Trim away the prefix new line.
|
// Trim away the prefix new line.
|
||||||
var comment = _comment[1:]
|
var goComment = _goComment[1:]
|
||||||
|
|
||||||
func TestComment(t *testing.T) {
|
func TestComment(t *testing.T) {
|
||||||
var authenticator = Main["cchat"].Interface("Authenticator")
|
var authenticator = Main[RootPath].Interface("Authenticator")
|
||||||
var authDoc = authenticator.Comment.GoString()
|
|
||||||
|
|
||||||
if eq := deep.Equal(comment, authDoc); eq != nil {
|
t.Run("godoc", func(t *testing.T) {
|
||||||
t.Fatal("Comment inequality:", eq)
|
godoc := authenticator.Comment.GoString(0)
|
||||||
}
|
|
||||||
|
if eq := deep.Equal(goComment, godoc); eq != nil {
|
||||||
|
t.Fatal("go comment inequality:", eq)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,3 @@
|
||||||
// +build ignore
|
package gob
|
||||||
|
|
||||||
package main
|
//go:generate go run ../../cmd/internal/cchat-gob-gen
|
||||||
|
|
||||||
//go:generate go run ./generator.go
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/gob"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/diamondburned/cchat/repository"
|
|
||||||
)
|
|
||||||
|
|
||||||
const output = "repository.gob"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
f, err := os.Create(output)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("Failed to create file:", err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
if err := gob.NewEncoder(f).Encode(repository.Main); err != nil {
|
|
||||||
os.Remove(output)
|
|
||||||
log.Fatalln("Failed to gob encode:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Binary file not shown.
|
@ -55,9 +55,15 @@ type GetterMethod struct {
|
||||||
Parameters []NamedType
|
Parameters []NamedType
|
||||||
// Returns is the list of named types returned from the function.
|
// Returns is the list of named types returned from the function.
|
||||||
Returns []NamedType
|
Returns []NamedType
|
||||||
// ReturnError is true if the function returns an error at the end of
|
// ErrorType is non-empty if the function returns an error at the end of
|
||||||
// returns.
|
// returns. For the most part, this field should be "error" if that is the
|
||||||
ReturnError bool
|
// case, but some methods may choose to extend the error base type.
|
||||||
|
ErrorType string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReturnError returns true if the method can error out.
|
||||||
|
func (m GetterMethod) ReturnError() bool {
|
||||||
|
return m.ErrorType != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetterMethod is a method that sets values. These methods must not do IO, and
|
// SetterMethod is a method that sets values. These methods must not do IO, and
|
||||||
|
@ -80,12 +86,19 @@ type IOMethod struct {
|
||||||
Parameters []NamedType
|
Parameters []NamedType
|
||||||
// ReturnValue is the return value in the function.
|
// ReturnValue is the return value in the function.
|
||||||
ReturnValue NamedType
|
ReturnValue NamedType
|
||||||
// ReturnError is true if the function returns an error at the end of
|
// ErrorType is non-empty if the function returns an error at the end of
|
||||||
// returns.
|
// returns. For the most part, this field should be "error" if that is the
|
||||||
ReturnError bool
|
// case, but some methods may choose to extend the error base type.
|
||||||
|
ErrorType string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerMethod is a method that uses a Container. These methods can do IO.
|
// ReturnError returns true if the method can error out.
|
||||||
|
func (m IOMethod) ReturnError() bool {
|
||||||
|
return m.ErrorType != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerMethod is a method that uses a Container. These methods can do IO
|
||||||
|
// and always return an error.
|
||||||
type ContainerMethod struct {
|
type ContainerMethod struct {
|
||||||
method
|
method
|
||||||
|
|
||||||
|
|
|
@ -332,7 +332,7 @@ var Main = Packages{
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
"github.com/diamondburned/cchat": {
|
RootPath: {
|
||||||
Comment: Comment{`
|
Comment: Comment{`
|
||||||
Package cchat is a set of stabilized interfaces for cchat
|
Package cchat is a set of stabilized interfaces for cchat
|
||||||
implementations, joining the backend and frontend together.
|
implementations, joining the backend and frontend together.
|
||||||
|
@ -681,29 +681,55 @@ var Main = Packages{
|
||||||
ChildType: "SessionRestorer",
|
ChildType: "SessionRestorer",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
Comment: Comment{`
|
||||||
|
AuthenticateError is the error returned when authenticating.
|
||||||
|
This error interface extends the normal error to allow backends
|
||||||
|
to implement multi-stage authentication if needed in a clean way
|
||||||
|
without needing any loops.
|
||||||
|
|
||||||
|
This interface satisfies the error interface.
|
||||||
|
`},
|
||||||
|
Name: "AuthenticateError",
|
||||||
|
Methods: []Method{
|
||||||
|
GetterMethod{
|
||||||
|
method: method{
|
||||||
|
Comment: Comment{`
|
||||||
|
Error returns the error as a string. This method
|
||||||
|
makes AuthenticateError satisfy the built-in error
|
||||||
|
interface.
|
||||||
|
`},
|
||||||
|
Name: "Error",
|
||||||
|
},
|
||||||
|
Returns: []NamedType{{Type: "string"}},
|
||||||
|
},
|
||||||
|
GetterMethod{
|
||||||
|
method: method{
|
||||||
|
Comment: Comment{`
|
||||||
|
NextStage optionally returns a slice of
|
||||||
|
Authenticator interfaces if the authentication
|
||||||
|
process requires another stage. It works similarly
|
||||||
|
to Service's Authenticate method, both of which
|
||||||
|
returns a slice of Authenticators.
|
||||||
|
|
||||||
|
If the error returned is an actual error, and that
|
||||||
|
the user should retry any of the authentication
|
||||||
|
fields, then NextStage could return nil to signify
|
||||||
|
the error. The frontend could reliably check nil on
|
||||||
|
this field to determine whether or not it should
|
||||||
|
recreate the authentication fields.
|
||||||
|
`},
|
||||||
|
Name: "NextStage",
|
||||||
|
},
|
||||||
|
Returns: []NamedType{{Type: "[]Authenticator"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
Comment: Comment{`
|
Comment: Comment{`
|
||||||
The authenticator interface allows for a multistage initial
|
The authenticator interface allows for a multistage initial
|
||||||
authentication API that the backend could use. Multistage is
|
authentication API that the backend could use. Multistage is
|
||||||
done by calling AuthenticateForm then Authenticate again forever
|
done by calling Authenticate and check for AuthenticateError's
|
||||||
until no errors are returned.
|
NextStage method.
|
||||||
|
|
||||||
var s *cchat.Session
|
|
||||||
var err error
|
|
||||||
|
|
||||||
for {
|
|
||||||
// Pseudo-function to render the form and return the results of those
|
|
||||||
// forms when the user confirms it.
|
|
||||||
outputs := renderAuthForm(svc.AuthenticateForm())
|
|
||||||
|
|
||||||
s, err = svc.Authenticate(outputs)
|
|
||||||
if err != nil {
|
|
||||||
renderError(errors.Wrap(err, "Error while authenticating"))
|
|
||||||
continue // retry
|
|
||||||
}
|
|
||||||
|
|
||||||
break // success
|
|
||||||
}
|
|
||||||
`},
|
`},
|
||||||
Name: "Authenticator",
|
Name: "Authenticator",
|
||||||
Methods: []Method{
|
Methods: []Method{
|
||||||
|
@ -753,7 +779,7 @@ var Main = Packages{
|
||||||
},
|
},
|
||||||
Parameters: []NamedType{{Type: "[]string"}},
|
Parameters: []NamedType{{Type: "[]string"}},
|
||||||
ReturnValue: NamedType{Type: "Session"},
|
ReturnValue: NamedType{Type: "Session"},
|
||||||
ReturnError: true,
|
ErrorType: "AuthenticateError",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
|
@ -770,7 +796,7 @@ var Main = Packages{
|
||||||
method: method{Name: "RestoreSession"},
|
method: method{Name: "RestoreSession"},
|
||||||
Parameters: []NamedType{{Type: "map[string]string"}},
|
Parameters: []NamedType{{Type: "map[string]string"}},
|
||||||
ReturnValue: NamedType{Type: "Session"},
|
ReturnValue: NamedType{Type: "Session"},
|
||||||
ReturnError: true,
|
ErrorType: "error",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
|
@ -785,12 +811,12 @@ var Main = Packages{
|
||||||
IOMethod{
|
IOMethod{
|
||||||
method: method{Name: "Configuration"},
|
method: method{Name: "Configuration"},
|
||||||
ReturnValue: NamedType{Type: "map[string]string"},
|
ReturnValue: NamedType{Type: "map[string]string"},
|
||||||
ReturnError: true,
|
ErrorType: "error",
|
||||||
},
|
},
|
||||||
IOMethod{
|
IOMethod{
|
||||||
method: method{Name: "SetConfiguration"},
|
method: method{Name: "SetConfiguration"},
|
||||||
Parameters: []NamedType{{Type: "map[string]string"}},
|
Parameters: []NamedType{{Type: "map[string]string"}},
|
||||||
ReturnError: true,
|
ErrorType: "error",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
|
@ -843,7 +869,7 @@ var Main = Packages{
|
||||||
`},
|
`},
|
||||||
Name: "Disconnect",
|
Name: "Disconnect",
|
||||||
},
|
},
|
||||||
ReturnError: true,
|
ErrorType: "error",
|
||||||
},
|
},
|
||||||
AsserterMethod{ChildType: "Commander"},
|
AsserterMethod{ChildType: "Commander"},
|
||||||
AsserterMethod{ChildType: "SessionSaver"},
|
AsserterMethod{ChildType: "SessionSaver"},
|
||||||
|
@ -930,7 +956,7 @@ var Main = Packages{
|
||||||
{Name: "words", Type: "[]string"},
|
{Name: "words", Type: "[]string"},
|
||||||
},
|
},
|
||||||
ReturnValue: NamedType{Type: "[]byte"},
|
ReturnValue: NamedType{Type: "[]byte"},
|
||||||
ReturnError: true,
|
ErrorType: "error",
|
||||||
},
|
},
|
||||||
AsserterMethod{ChildType: "Completer"},
|
AsserterMethod{ChildType: "Completer"},
|
||||||
},
|
},
|
||||||
|
@ -1027,7 +1053,7 @@ var Main = Packages{
|
||||||
Parameters: []NamedType{
|
Parameters: []NamedType{
|
||||||
{Type: "SendableMessage"},
|
{Type: "SendableMessage"},
|
||||||
},
|
},
|
||||||
ReturnError: true,
|
ErrorType: "error",
|
||||||
},
|
},
|
||||||
GetterMethod{
|
GetterMethod{
|
||||||
method: method{
|
method: method{
|
||||||
|
@ -1067,9 +1093,9 @@ var Main = Packages{
|
||||||
`},
|
`},
|
||||||
Name: "RawContent",
|
Name: "RawContent",
|
||||||
},
|
},
|
||||||
Parameters: []NamedType{{Name: "id", Type: "ID"}},
|
Parameters: []NamedType{{Name: "id", Type: "ID"}},
|
||||||
Returns: []NamedType{{Type: "string"}},
|
Returns: []NamedType{{Type: "string"}},
|
||||||
ReturnError: true,
|
ErrorType: "error",
|
||||||
},
|
},
|
||||||
IOMethod{
|
IOMethod{
|
||||||
method: method{
|
method: method{
|
||||||
|
@ -1084,7 +1110,7 @@ var Main = Packages{
|
||||||
{Name: "id", Type: "ID"},
|
{Name: "id", Type: "ID"},
|
||||||
{Name: "content", Type: "string"},
|
{Name: "content", Type: "string"},
|
||||||
},
|
},
|
||||||
ReturnError: true,
|
ErrorType: "error",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
|
@ -1123,7 +1149,7 @@ var Main = Packages{
|
||||||
{Name: "action", Type: "string"},
|
{Name: "action", Type: "string"},
|
||||||
{Name: "id", Type: "ID"},
|
{Name: "id", Type: "ID"},
|
||||||
},
|
},
|
||||||
ReturnError: true,
|
ErrorType: "error",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
|
@ -1187,7 +1213,7 @@ var Main = Packages{
|
||||||
{"before", "ID"},
|
{"before", "ID"},
|
||||||
{"msgc", "MessagesContainer"},
|
{"msgc", "MessagesContainer"},
|
||||||
},
|
},
|
||||||
ReturnError: true,
|
ErrorType: "error",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
|
@ -1262,7 +1288,7 @@ var Main = Packages{
|
||||||
`},
|
`},
|
||||||
Name: "Typing",
|
Name: "Typing",
|
||||||
},
|
},
|
||||||
ReturnError: true,
|
ErrorType: "error",
|
||||||
},
|
},
|
||||||
GetterMethod{
|
GetterMethod{
|
||||||
method: method{
|
method: method{
|
||||||
|
|
|
@ -17,7 +17,7 @@ func TestGob(t *testing.T) {
|
||||||
|
|
||||||
t.Log("Marshaled; total bytes:", buf.Len())
|
t.Log("Marshaled; total bytes:", buf.Len())
|
||||||
|
|
||||||
var unmarshaled Repositories
|
var unmarshaled Packages
|
||||||
|
|
||||||
if err := gob.NewDecoder(&buf).Decode(&unmarshaled); err != nil {
|
if err := gob.NewDecoder(&buf).Decode(&unmarshaled); err != nil {
|
||||||
t.Fatal("Failed to gob decode:", err)
|
t.Fatal("Failed to gob decode:", err)
|
||||||
|
|
Loading…
Reference in a new issue