Programming Go 1 year,10 months ago
In language Go,as a matter of fact,there are two basic essences: executed files,and packages. In this article I suggest to consider the second on a small example.
The package is a library of functions and structures. According to the destination it reminds standard,all well-known,linkuemye libraries. The package in Go defines visibility area. If the name of variables or structures begins with a small letter,they local (area of visibility of a package),if with big,the exported. Local structures and functions can be used only in a package,global inside and out of a package. The let feature is easy be know on an example of work with a package json,a part of standard libraries of language.
The similar code will return an error.
type Link struct {
name string
url string
title string
class string
}
links := make(map[string]Link)
if err = json.Unmarshal(response,&links;); err != nil {
return err
}
The matter is that we use functions from a package json,transferring structure c fields of local visibility (in function Unmarshal To structure fields Link Simply there is no access).
The package code should settle down according to his name that is if the package is called ru/sezn/server,That files *.go Will be in a folder server which will be podpapkoj sezn and ru.
Let's consider a package of a simple Web server which is used in ours a web applications: http://sezn.ru/ and http://hashcode.ru/
In language Go there is an own library representing the http-server. As the majority of developers have more than one site,to use directly the built in http-server it will not turn out (in system there is only one 80 port). For start we will use the module fastCGI Web server Apache2. The file of adjustment virtual hotsa applications is more low resulted.
<VirtualHost *:80>
ServerAdmin webmaster@hashcode.ru
DocumentRoot /path/to/bin/
ServerName sezn.ru
ErrorLog /var/log/apache2/sezn_error.log
LogLevel warn
CustomLog /var/log/apache2/sezn_warning.log combined
AddHandler fastcgi-script our_bin
FastCgiExternalServer /path/to/bin/our_bin -host 127.0.0.1:3489
RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /our_bin [QSA,L]
</VirtualHost>
The server package is realised in the form of simple structure with a set of methods for processing of inquiries of files,registration vjushek,checks "kapchi" and so on. At the heart of system of routeing we use library Gorilla (http://www.gorillatoolkit.org/). For support kapchi was the library https://github.com/dchest/captcha is taken.
The basic structure of the server:
type Server struct {
Router *mux.Router
Transport string
Addres string
MediaPath string
CachedFiles map[string]*CachedFile
fn404 func(w http.ResponseWriter,r *http.Request)
}
For faster work we use keshirvoanie all files in a folder with mediej.
type CachedFile struct {
FileName string
FullPath string
FilePath string
FileExt string
FileData []byte
}
The server realises the following public interface.
AddNamedHandler(pattern string,handler func(http.ResponseWriter,*http.Request),name string)
AddHandler(pattern string,*http.Request))
Reverse(name string) *mux.Route
Run() error
SetRootMediaPath(path string)
Set404ErrorHandler(fn func(w http.ResponseWriter,r *http.Request))
ServeHTTP(w http.ResponseWriter,r *http.Request)
And tazhe the interface with area of visibility of a package.
cacheFiles()
renderFile(w http.ResponseWriter,filename string) error
During initialization,we only create the basic structures.
func InitServer(transport,addres string) *Server {
server := &Server;{Router: &mux.Router;{},Transport: transport,Addres: addres}
return server
}
Then,on a course of initialization of modules,the basic application adds the called/not called functions output agents causing a method AddNamedHandler Or AddHandler.
Code of function of registration of the output agent.
func (server *Server) AddNamedHandler(pattern string,name string) {
server.Router.HandleFunc(pattern,handler).Name(name)
}
For server start it is necessary to cause method Run. In it we keshiruem files (to a question on caching http://Meta.hashcode.ru/questions/1158/) also register media the output agent fastCGI the report.
func (server *Server) Run() error {
server.cacheFiles()
l,err := net.Listen(server.Transport,server.Addres)
if err != nil {
return err
}
fcgi.Serve(l,server.Router)
return nil
}
Before method Run will be caused,it is necessary to establish the output agent who will be caused if the required file is not found.
func (server *Server) Set404ErrorHandler(fn func(w http.ResponseWriter,r *http.Request)) {
server.fn404 = fn
server.Router.NotFoundHandler = server
}
Here there is a thin moment,we register the output agent of an error 404,transferring to library Gorilla our server. The server realises the interface of processing HTTP of inquiries. For it the method responds ServeHTTP.
func (server *Server) ServeHTTP(w http.ResponseWriter,r *http.Request) {
err := server.renderFile(w,r.URL.Path)
if err != nil {
w.Header().Set("Content-Type","text/html; charset=utf-8")
w.WriteHeader(http.StatusNotFound)
server.fn404(w,r)
}
}
We register output agents of all vjushek in system of routeing of library Gorilla. If the output agent is not found,we try to find a file,with such name. If the file is not present,we cause the output agent of an error 404.
Method of reading of media of files in memory:
func (server *Server) cacheFiles() {
server.CachedFiles = make(map[string]*CachedFile)
dir,_ := filepath.Abs(server.MediaPath)
filepath.Walk(dir,func(path string,info os.FileInfo,err error) error {
if info.IsDir() {
return nil
}
file,err := IoUtil.ReadFile(path)
filePath := strings.Replace(path,dir,"",-1)
server.CachedFiles[filePath] = &CachedFile; {
FileName: info.Name(),
FullPath: path,
FilePath: filePath,
FileExt: filepath.Ext(path),
FileData: file,
}
return nil
});
}
At the moment of inquiry of a file,it is necessary for us to look only at occurrence of a corresponding way to the dictionary with files and to generate the answer. If file with we request the address it is not found,we will try to find it on a disk.
func (server *Server) renderFile(w http.ResponseWriter,filename string) error {
var file []byte
var ext string
var err error
if cachedFile,exist := server.CachedFiles[filename]; exist {
file = cachedFile.FileData
ext = cachedFile.FileExt
} else {
file,err = IoUtil.ReadFile(server.MediaPath + filename)
if err != nil {
return err
}
ext = filepath.Ext(server.MediaPath + filename)
}
if ext != "" {
w.Header().Set("Content-Type",mime.TypeByExtension(ext))
}
if file != nil {
w.Write(file)
}
return nil
}
The name “server” is far not the unique. We place packages using notation Java. When we will want to export a package,the full name will look as ru/sezn/server. For creation of a package we use the program delivered with language.
go get ru/sezn/server
Here basically and all. I will be glad to answer questions in comments to a post or in a corresponding branch on HeshKode (http://hashcode.ru/questions/tagged/go/).
P. S. The given package was altered last time under Go RC1 and can not work with later/early version of language.
http://sysmagazine.com/posts/178539/
原文链接:https://www.f2er.com/go/190478.html