Решение на Concurrent Tasks от Катя Спасова

Обратно към всички решения

Към профила на Катя Спасова

Резултати

  • 5 точки от тестове
  • 0 бонус точки
  • 5 точки общо
  • 5 успешни тест(а)
  • 5 неуспешни тест(а)

Код

package main
import (
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"sync"
)
// Creates a new library
func NewLibrary(librarians int) Library {
m := make(map[string]*Book)
librariansChan := make(chan Librarian, librarians)
return &FancyLibrary{books: m, librarians: librariansChan, mutex: sync.Mutex{}}
}
// Librarian working in the library
type Librarian struct {
request chan LibraryRequest
response chan LibraryResponse
library *FancyLibrary
}
// The librarian waits for requests and helps borrowing a book,
// returning a book, getting information about a book
func (librarian *Librarian) serve() {
go func() {
for {
message, ok := <-librarian.request
if ok {
isbn := message.GetISBN()
requestType := message.GetType()
switch requestType {
case BorrowBook:
libraryResponse := librarian.borrowBook(isbn)
librarian.response <- &libraryResponse
case ReturnBook:
libraryResponse := librarian.returnBook(isbn)
librarian.response <- &libraryResponse
case GetAvailability:
libraryResponse := librarian.getAvailability(isbn)
librarian.response <- &libraryResponse
default:
librarian.response <- &CoolLibraryResponse{book: nil,
err: errors.New("Невалидна заявка")}
}
} else {
break
}
}
}()
}
// Reduces the available count for book with given isbn
// Returns information about the book
// Returns error if the book is not in the library or all copies are taken
func (librarian *Librarian) borrowBook(isbn string) CoolLibraryResponse {
librarian.library.mutex.Lock()
book, ok := librarian.library.books[isbn]
var err error = nil
if !ok {
err = errors.New("Непозната книга " + isbn)
} else {
if book.availableCount == 0 {
err = errors.New("Няма наличност на книга " + isbn)
}
book.availableCount -= 1
librarian.library.books[isbn] = book
}
librarian.library.mutex.Unlock()
return CoolLibraryResponse{book: book, err: err}
}
// Increases the available count for book with given isbn
// Returns information about the book
// Returns error if the book is not in the library
// or all the books of this type are already in the library
func (librarian *Librarian) returnBook(isbn string) CoolLibraryResponse {
librarian.library.mutex.Lock()
book, ok := librarian.library.books[isbn]
var err error = nil
if !ok {
err = errors.New("Непозната книга " + isbn)
} else {
if book.availableCount == book.registeredCount {
err = errors.New("Всички копия са налични " + isbn)
}
book.availableCount += 1
librarian.library.books[isbn] = book
}
librarian.library.mutex.Unlock()
return CoolLibraryResponse{book: book, err: err}
}
// Returns information about the book
// Returns error if the book is not in the library
func (librarian *Librarian) getAvailability(isbn string) CoolLibraryResponse {
librarian.library.mutex.Lock()
book, ok := librarian.library.books[isbn]
var err error = nil
if !ok {
err = errors.New("Непозната книга " + isbn)
}
librarian.library.mutex.Unlock()
return CoolLibraryResponse{book: book, err: err}
}
type Person struct {
FirstName string `xml:"first_name" json:"first_name"`
LastName string `xml:"last_name" json:"last_name"`
}
// The type for the books that are stored in the library
type Book struct {
ISBN string `xml:"isbn,attr"`
Title string `xml:"title"`
Author Person `xml:"author"`
registeredCount int
availableCount int
}
// Returns a string representation of the book
func (book Book) String() string {
return "Book: [" + book.ISBN + "] " + book.Title + " от " + book.Author.FirstName +
" " + book.Author.LastName
}
// The library
type FancyLibrary struct {
books map[string]*Book
librarians chan Librarian
mutex sync.Mutex
}
// Adds a book to the library
// Returns the count of all available copies in the library
// Return an error of the number of copies is more than 4
func (library *FancyLibrary) addBook(book *Book) (int, error) {
// Assuming that books with same ISBN are the same
library.mutex.Lock()
same_book := library.books[book.ISBN]
if same_book != nil {
// there are already 4 copies of the book - return error
if same_book.registeredCount == 4 {
return 4, errors.New("Има 4 копия на книга " + book.ISBN)
}
same_book.registeredCount += 1
same_book.availableCount += 1
} else {
book.registeredCount = 1
book.availableCount = 1
library.books[book.ISBN] = book
}
library.mutex.Unlock()
return library.books[book.ISBN].availableCount, nil
}
// Add a book from json
// Returns the count of all available copies in the library
// Return an error of the number of copies is more than 4
func (library *FancyLibrary) AddBookJSON(data []byte) (int, error) {
book := new(Book)
err := json.Unmarshal(data, book)
if err != nil {
return 0, err
}
return library.addBook(book)
}
// Add a book from xml
// Returns the count of all available copies in the library
// Return an error of the number of copies is more than 4
func (library *FancyLibrary) AddBookXML(data []byte) (int, error) {
book := new(Book)
err := xml.Unmarshal(data, book)
if err != nil {
return 0, err
}
return library.addBook(book)
}
// Gets a free librarian to serve requests
// Librarians are fixed - passed as an argument to NewLibrary func
// Blocks if all librarians are busy
// Returns two channels
// write channel - for sending of requests
// read channel - for receiving results
// On closing the request (write channel) the librarian is released
func (library *FancyLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
// The librarians can get up to 100 requests before someone reads the response
request := make(chan LibraryRequest, 100)
response := make(chan LibraryResponse, 100)
librarian := Librarian{request: request, response: response, library: library}
library.librarians <- librarian
librarian.serve()
return librarian.request, librarian.response
}
// Available types of requests
const (
_ = iota
BorrowBook
ReturnBook
GetAvailability
)
// The type for the requests the librarians work with
type CoolLibraryRequest struct {
isbn string
requestType int
}
// Return the type of the request:
// 1 - Borrow book
// 2 - Return book
// 3 - Get availability information about book
func (request *CoolLibraryRequest) GetType() int {
return request.requestType
}
// Return the isbn of the book for which is the request
func (request *CoolLibraryRequest) GetISBN() string {
return request.isbn
}
// The type for the requests the librarians work with
type CoolLibraryResponse struct {
book *Book
err error
}
// gets book content, an object implementing Stringer
// If the book does not exist the first result is nil
// returns an error if it has occured
// when "Return book", the content is not attached
func (response *CoolLibraryResponse) GetBook() (fmt.Stringer, error) {
if response.err != nil {
return nil, response.err
}
if response != nil && response.book != nil {
return response.book, nil
} else {
return nil, errors.New("Празен отговор")
}
}
// available - how many books are available after the request is performed
// registered - how many copies are registered from this book (маx 4).
func (response *CoolLibraryResponse) GetAvailability() (available int, registered int) {
if response != nil && response.book != nil {
return response.book.availableCount, response.book.registeredCount
} else {
return 0, 0
}
}
type Library interface {
// Добавя книга от json
// Oтговаря с общия брой копия в библиотеката (не само наличните).
// Aко са повече от 4 - връща грешка
AddBookJSON(data []byte) (int, error)
// Добавя книга от xml
// Oтговаря с общия брой копия в библиотеката (не само наличните).
// Ако са повече от 4 - връщаме грешка
AddBookXML(data []byte) (int, error)
// Ангажира свободен "библиотекар" да ни обработва заявките.
// Библиотекарите са фиксиран брой - подават се като параметър на NewLibrary
// Блокира ако всички библиотекари са заети.
// Връщат се два канала:
// първият е само за писане - по него ще изпращаме заявките
// вторият е само за четене - по него ще получаваме отговорите.
// Ако затворим канала със заявките - освобождаваме библиотекаря.
Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
}
type LibraryRequest interface {
// Тип на заявката:
// 1 - Borrow book
// 2 - Return book
// 3 - Get availability information about book
GetType() int
// Връща isbn на книгата, за която се отнася Request-a
GetISBN() string
}
type LibraryResponse interface {
// Ако книгата съществува/налична е - обект имплементиращ Stringer (повече информация по-долу)
// Aко книгата не съществува първият резултат е nil.
// Връща се и подобаващa грешка (виж по-долу) - ако такава е възникнала.
// Когато се е резултат на заявка от тип 2 (Return book) - не е нужно да я закачаме към отговора.
GetBook() (fmt.Stringer, error)
// available - Колко наличности от книгата имаме останали след изпълнението на заявката.
// Тоест, ако сме имали 3 копия от Х и това е отговор на Take заявка - тук ще има 2.
// registered - Колко копия от тази книга има регистрирани в библиотеката (макс 4).
GetAvailability() (available int, registered int)
}

Лог от изпълнението

PASS
ok  	_/tmp/d20151207-5667-t1u08y	0.003s
panic: test timed out after 1s

goroutine 22 [running]:
testing.startAlarm.func1()
	/usr/local/go/src/testing/testing.go:703 +0x132
created by time.goFunc
	/usr/local/go/src/time/sleep.go:129 +0x3a

goroutine 1 [chan receive]:
testing.RunTests(0x645860, 0x6e8ce0, 0xa, 0xa, 0x6eb901)
	/usr/local/go/src/testing/testing.go:562 +0x8ad
testing.(*M).Run(0xc82003fef8, 0xc82003ff28)
	/usr/local/go/src/testing/testing.go:494 +0x70
main.main()
	_/tmp/d20151207-5667-t1u08y/_test/_testmain.go:72 +0x116

goroutine 20 [chan receive]:
_/tmp/d20151207-5667-t1u08y.TestAddBookJSON(0xc8200cc000)
	/tmp/d20151207-5667-t1u08y/solution_test.go:125 +0x15d2
testing.tRunner(0xc8200cc000, 0x6e8cf8)
	/usr/local/go/src/testing/testing.go:456 +0x98
created by testing.RunTests
	/usr/local/go/src/testing/testing.go:561 +0x86d

goroutine 21 [semacquire]:
sync.runtime_Semacquire(0xc82005c094)
	/usr/local/go/src/runtime/sema.go:43 +0x26
sync.(*Mutex).Lock(0xc82005c090)
	/usr/local/go/src/sync/mutex.go:82 +0x1c4
_/tmp/d20151207-5667-t1u08y.(*Librarian).borrowBook(0xc82005c300, 0x5f2590, 0xa, 0x0, 0x0, 0x0)
	/tmp/d20151207-5667-t1u08y/solution.go:59 +0x5e
_/tmp/d20151207-5667-t1u08y.(*Librarian).serve.func1(0xc82005c300)
	/tmp/d20151207-5667-t1u08y/solution.go:36 +0x11b
created by _/tmp/d20151207-5667-t1u08y.(*Librarian).serve
	/tmp/d20151207-5667-t1u08y/solution.go:52 +0x35
exit status 2
FAIL	_/tmp/d20151207-5667-t1u08y	1.006s
panic: test timed out after 1s

goroutine 3 [running]:
testing.startAlarm.func1()
	/usr/local/go/src/testing/testing.go:703 +0x132
created by time.goFunc
	/usr/local/go/src/time/sleep.go:129 +0x3a

goroutine 1 [chan receive]:
testing.RunTests(0x645860, 0x6e8ce0, 0xa, 0xa, 0x6eb901)
	/usr/local/go/src/testing/testing.go:562 +0x8ad
testing.(*M).Run(0xc82003fef8, 0xc82003ff28)
	/usr/local/go/src/testing/testing.go:494 +0x70
main.main()
	_/tmp/d20151207-5667-t1u08y/_test/_testmain.go:72 +0x116

goroutine 20 [chan receive]:
_/tmp/d20151207-5667-t1u08y.TestAddBookXML(0xc8200cc000)
	/tmp/d20151207-5667-t1u08y/solution_test.go:155 +0x15d2
testing.tRunner(0xc8200cc000, 0x6e8d10)
	/usr/local/go/src/testing/testing.go:456 +0x98
created by testing.RunTests
	/usr/local/go/src/testing/testing.go:561 +0x86d

goroutine 21 [semacquire]:
sync.runtime_Semacquire(0xc82005c094)
	/usr/local/go/src/runtime/sema.go:43 +0x26
sync.(*Mutex).Lock(0xc82005c090)
	/usr/local/go/src/sync/mutex.go:82 +0x1c4
_/tmp/d20151207-5667-t1u08y.(*Librarian).borrowBook(0xc8200e42c0, 0x5f2590, 0xa, 0x0, 0x0, 0x0)
	/tmp/d20151207-5667-t1u08y/solution.go:59 +0x5e
_/tmp/d20151207-5667-t1u08y.(*Librarian).serve.func1(0xc8200e42c0)
	/tmp/d20151207-5667-t1u08y/solution.go:36 +0x11b
created by _/tmp/d20151207-5667-t1u08y.(*Librarian).serve
	/tmp/d20151207-5667-t1u08y/solution.go:52 +0x35
exit status 2
FAIL	_/tmp/d20151207-5667-t1u08y	1.006s
panic: test timed out after 1s

goroutine 17 [running]:
testing.startAlarm.func1()
	/usr/local/go/src/testing/testing.go:703 +0x132
created by time.goFunc
	/usr/local/go/src/time/sleep.go:129 +0x3a

goroutine 1 [chan receive]:
testing.RunTests(0x645860, 0x6e8ce0, 0xa, 0xa, 0x6eb901)
	/usr/local/go/src/testing/testing.go:562 +0x8ad
testing.(*M).Run(0xc82003fef8, 0xc82003ff28)
	/usr/local/go/src/testing/testing.go:494 +0x70
main.main()
	_/tmp/d20151207-5667-t1u08y/_test/_testmain.go:72 +0x116

goroutine 6 [chan receive]:
_/tmp/d20151207-5667-t1u08y.TestAddBookCombined(0xc8200b4000)
	/tmp/d20151207-5667-t1u08y/solution_test.go:189 +0x195b
testing.tRunner(0xc8200b4000, 0x6e8d28)
	/usr/local/go/src/testing/testing.go:456 +0x98
created by testing.RunTests
	/usr/local/go/src/testing/testing.go:561 +0x86d

goroutine 7 [semacquire]:
sync.runtime_Semacquire(0xc82000e334)
	/usr/local/go/src/runtime/sema.go:43 +0x26
sync.(*Mutex).Lock(0xc82000e330)
	/usr/local/go/src/sync/mutex.go:82 +0x1c4
_/tmp/d20151207-5667-t1u08y.(*Librarian).borrowBook(0xc82000f920, 0x5f2590, 0xa, 0x0, 0x0, 0x0)
	/tmp/d20151207-5667-t1u08y/solution.go:59 +0x5e
_/tmp/d20151207-5667-t1u08y.(*Librarian).serve.func1(0xc82000f920)
	/tmp/d20151207-5667-t1u08y/solution.go:36 +0x11b
created by _/tmp/d20151207-5667-t1u08y.(*Librarian).serve
	/tmp/d20151207-5667-t1u08y/solution.go:52 +0x35
exit status 2
FAIL	_/tmp/d20151207-5667-t1u08y	1.006s
PASS
ok  	_/tmp/d20151207-5667-t1u08y	0.004s
PASS
ok  	_/tmp/d20151207-5667-t1u08y	0.004s
--- FAIL: TestBookStringer (0.00s)
	solution_test.go:82: [solution_test.go:281] Expected:
		[0954540018] Who Said the Race is Over? от Anno Birkin
		Got:
		Book: [0954540018] Who Said the Race is Over? от Anno Birkin
		Context: Book as fmt.Stringer
FAIL
exit status 1
FAIL	_/tmp/d20151207-5667-t1u08y	0.004s
PASS
ok  	_/tmp/d20151207-5667-t1u08y	0.003s
panic: test timed out after 1s

goroutine 8 [running]:
testing.startAlarm.func1()
	/usr/local/go/src/testing/testing.go:703 +0x132
created by time.goFunc
	/usr/local/go/src/time/sleep.go:129 +0x3a

goroutine 1 [chan receive]:
testing.RunTests(0x645860, 0x6e8ce0, 0xa, 0xa, 0x6eb901)
	/usr/local/go/src/testing/testing.go:562 +0x8ad
testing.(*M).Run(0xc82003fef8, 0xc82003ff28)
	/usr/local/go/src/testing/testing.go:494 +0x70
main.main()
	_/tmp/d20151207-5667-t1u08y/_test/_testmain.go:72 +0x116

goroutine 6 [chan receive]:
_/tmp/d20151207-5667-t1u08y.TestReturnSomeBooks(0xc8200b4000)
	/tmp/d20151207-5667-t1u08y/solution_test.go:323 +0x455
testing.tRunner(0xc8200b4000, 0x6e8da0)
	/usr/local/go/src/testing/testing.go:456 +0x98
created by testing.RunTests
	/usr/local/go/src/testing/testing.go:561 +0x86d

goroutine 7 [semacquire]:
sync.runtime_Semacquire(0xc82000e334)
	/usr/local/go/src/runtime/sema.go:43 +0x26
sync.(*Mutex).Lock(0xc82000e330)
	/usr/local/go/src/sync/mutex.go:82 +0x1c4
_/tmp/d20151207-5667-t1u08y.(*Librarian).borrowBook(0xc82000e340, 0x5f2590, 0xa, 0x0, 0x0, 0x0)
	/tmp/d20151207-5667-t1u08y/solution.go:59 +0x5e
_/tmp/d20151207-5667-t1u08y.(*Librarian).serve.func1(0xc82000e340)
	/tmp/d20151207-5667-t1u08y/solution.go:36 +0x11b
created by _/tmp/d20151207-5667-t1u08y.(*Librarian).serve
	/tmp/d20151207-5667-t1u08y/solution.go:52 +0x35
exit status 2
FAIL	_/tmp/d20151207-5667-t1u08y	1.006s
PASS
ok  	_/tmp/d20151207-5667-t1u08y	0.006s

История (1 версия и 1 коментар)

Катя обнови решението на 05.12.2015 17:31 (преди над 2 години)

+package main
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "sync"
+)
+
+// Creates a new library
+func NewLibrary(librarians int) Library {
+ m := make(map[string]*Book)
+ librariansChan := make(chan Librarian, librarians)
+ return &FancyLibrary{books: m, librarians: librariansChan, mutex: sync.Mutex{}}
+}
+
+// Librarian working in the library
+type Librarian struct {
+ request chan LibraryRequest
+ response chan LibraryResponse
+ library *FancyLibrary
+}
+
+// The librarian waits for requests and helps borrowing a book,
+// returning a book, getting information about a book
+func (librarian *Librarian) serve() {
+ go func() {
+ for {
+ message, ok := <-librarian.request
+ if ok {
+ isbn := message.GetISBN()
+ requestType := message.GetType()
+ switch requestType {
+ case BorrowBook:
+ libraryResponse := librarian.borrowBook(isbn)
+ librarian.response <- &libraryResponse
+ case ReturnBook:
+ libraryResponse := librarian.returnBook(isbn)
+ librarian.response <- &libraryResponse
+ case GetAvailability:
+ libraryResponse := librarian.getAvailability(isbn)
+ librarian.response <- &libraryResponse
+ default:
+ librarian.response <- &CoolLibraryResponse{book: nil,
+ err: errors.New("Невалидна заявка")}
+ }
+ } else {
+ break
+ }
+ }
+ }()
+}
+
+// Reduces the available count for book with given isbn
+// Returns information about the book
+// Returns error if the book is not in the library or all copies are taken
+func (librarian *Librarian) borrowBook(isbn string) CoolLibraryResponse {
+ librarian.library.mutex.Lock()
+ book, ok := librarian.library.books[isbn]
+ var err error = nil
+ if !ok {
+ err = errors.New("Непозната книга " + isbn)
+ } else {
+ if book.availableCount == 0 {
+ err = errors.New("Няма наличност на книга " + isbn)
+ }
+
+ book.availableCount -= 1
+ librarian.library.books[isbn] = book
+ }
+ librarian.library.mutex.Unlock()
+ return CoolLibraryResponse{book: book, err: err}
+}
+
+// Increases the available count for book with given isbn
+// Returns information about the book
+// Returns error if the book is not in the library
+// or all the books of this type are already in the library
+func (librarian *Librarian) returnBook(isbn string) CoolLibraryResponse {
+ librarian.library.mutex.Lock()
+ book, ok := librarian.library.books[isbn]
+ var err error = nil
+ if !ok {
+ err = errors.New("Непозната книга " + isbn)
+ } else {
+ if book.availableCount == book.registeredCount {
+ err = errors.New("Всички копия са налични " + isbn)
+ }
+
+ book.availableCount += 1
+ librarian.library.books[isbn] = book
+ }
+ librarian.library.mutex.Unlock()
+ return CoolLibraryResponse{book: book, err: err}
+}
+
+// Returns information about the book
+// Returns error if the book is not in the library
+func (librarian *Librarian) getAvailability(isbn string) CoolLibraryResponse {
+ librarian.library.mutex.Lock()
+ book, ok := librarian.library.books[isbn]
+ var err error = nil
+ if !ok {
+ err = errors.New("Непозната книга " + isbn)
+ }
+ librarian.library.mutex.Unlock()
+ return CoolLibraryResponse{book: book, err: err}
+}
+
+type Person struct {
+ FirstName string `xml:"first_name" json:"first_name"`
+ LastName string `xml:"last_name" json:"last_name"`
+}
+
+// The type for the books that are stored in the library
+type Book struct {
+ ISBN string `xml:"isbn,attr"`
+ Title string `xml:"title"`
+ Author Person `xml:"author"`
+ registeredCount int
+ availableCount int
+}
+
+// Returns a string representation of the book
+func (book Book) String() string {
+ return "Book: [" + book.ISBN + "] " + book.Title + " от " + book.Author.FirstName +
+ " " + book.Author.LastName
+}
+
+// The library
+type FancyLibrary struct {
+ books map[string]*Book
+ librarians chan Librarian
+ mutex sync.Mutex
+}
+
+// Adds a book to the library
+// Returns the count of all available copies in the library
+// Return an error of the number of copies is more than 4
+func (library *FancyLibrary) addBook(book *Book) (int, error) {
+ // Assuming that books with same ISBN are the same
+ library.mutex.Lock()
+ same_book := library.books[book.ISBN]
+ if same_book != nil {
+ // there are already 4 copies of the book - return error
+ if same_book.registeredCount == 4 {
+ return 4, errors.New("Има 4 копия на книга " + book.ISBN)
+ }
+ same_book.registeredCount += 1
+ same_book.availableCount += 1
+ } else {
+ book.registeredCount = 1
+ book.availableCount = 1
+ library.books[book.ISBN] = book
+ }
+ library.mutex.Unlock()
+ return library.books[book.ISBN].availableCount, nil
+}
+
+// Add a book from json
+// Returns the count of all available copies in the library
+// Return an error of the number of copies is more than 4
+func (library *FancyLibrary) AddBookJSON(data []byte) (int, error) {
+ book := new(Book)
+ err := json.Unmarshal(data, book)
+ if err != nil {
+ return 0, err
+ }
+ return library.addBook(book)
+}
+
+// Add a book from xml
+// Returns the count of all available copies in the library
+// Return an error of the number of copies is more than 4
+func (library *FancyLibrary) AddBookXML(data []byte) (int, error) {
+ book := new(Book)
+ err := xml.Unmarshal(data, book)
+ if err != nil {
+ return 0, err
+ }
+ return library.addBook(book)
+}
+
+// Gets a free librarian to serve requests
+// Librarians are fixed - passed as an argument to NewLibrary func
+// Blocks if all librarians are busy
+// Returns two channels
+// write channel - for sending of requests
+// read channel - for receiving results
+// On closing the request (write channel) the librarian is released
+func (library *FancyLibrary) Hello() (chan<- LibraryRequest, <-chan LibraryResponse) {
+ // The librarians can get up to 100 requests before someone reads the response
+ request := make(chan LibraryRequest, 100)
+ response := make(chan LibraryResponse, 100)
+ librarian := Librarian{request: request, response: response, library: library}
+ library.librarians <- librarian
+ librarian.serve()
+ return librarian.request, librarian.response
+}
+
+// Available types of requests
+const (
+ _ = iota
+ BorrowBook
+ ReturnBook
+ GetAvailability
+)
+
+// The type for the requests the librarians work with
+type CoolLibraryRequest struct {
+ isbn string
+ requestType int
+}
+
+// Return the type of the request:
+// 1 - Borrow book
+// 2 - Return book
+// 3 - Get availability information about book
+func (request *CoolLibraryRequest) GetType() int {
+ return request.requestType
+}
+
+// Return the isbn of the book for which is the request
+func (request *CoolLibraryRequest) GetISBN() string {
+ return request.isbn
+}
+
+// The type for the requests the librarians work with
+type CoolLibraryResponse struct {
+ book *Book
+ err error
+}
+
+// gets book content, an object implementing Stringer
+// If the book does not exist the first result is nil
+// returns an error if it has occured
+// when "Return book", the content is not attached
+func (response *CoolLibraryResponse) GetBook() (fmt.Stringer, error) {
+ if response.err != nil {
+ return nil, response.err
+ }
+ if response != nil && response.book != nil {
+ return response.book, nil
+ } else {
+ return nil, errors.New("Празен отговор")
+ }
+}
+
+// available - how many books are available after the request is performed
+// registered - how many copies are registered from this book (маx 4).
+func (response *CoolLibraryResponse) GetAvailability() (available int, registered int) {
+ if response != nil && response.book != nil {
+ return response.book.availableCount, response.book.registeredCount
+ } else {
+ return 0, 0
+ }
+}
+
+type Library interface {
+
+ // Добавя книга от json
+ // Oтговаря с общия брой копия в библиотеката (не само наличните).
+ // Aко са повече от 4 - връща грешка
+ AddBookJSON(data []byte) (int, error)
+
+ // Добавя книга от xml
+ // Oтговаря с общия брой копия в библиотеката (не само наличните).
+ // Ако са повече от 4 - връщаме грешка
+ AddBookXML(data []byte) (int, error)
+
+ // Ангажира свободен "библиотекар" да ни обработва заявките.
+ // Библиотекарите са фиксиран брой - подават се като параметър на NewLibrary
+ // Блокира ако всички библиотекари са заети.
+ // Връщат се два канала:
+ // първият е само за писане - по него ще изпращаме заявките
+ // вторият е само за четене - по него ще получаваме отговорите.
+ // Ако затворим канала със заявките - освобождаваме библиотекаря.
+ Hello() (chan<- LibraryRequest, <-chan LibraryResponse)
+}
+
+type LibraryRequest interface {
+ // Тип на заявката:
+ // 1 - Borrow book
+ // 2 - Return book
+ // 3 - Get availability information about book
+ GetType() int
+
+ // Връща isbn на книгата, за която се отнася Request-a
+ GetISBN() string
+}
+
+type LibraryResponse interface {
+ // Ако книгата съществува/налична е - обект имплементиращ Stringer (повече информация по-долу)
+ // Aко книгата не съществува първият резултат е nil.
+ // Връща се и подобаващa грешка (виж по-долу) - ако такава е възникнала.
+ // Когато се е резултат на заявка от тип 2 (Return book) - не е нужно да я закачаме към отговора.
+ GetBook() (fmt.Stringer, error)
+
+ // available - Колко наличности от книгата имаме останали след изпълнението на заявката.
+ // Тоест, ако сме имали 3 копия от Х и това е отговор на Take заявка - тук ще има 2.
+ // registered - Колко копия от тази книга има регистрирани в библиотеката (макс 4).
+ GetAvailability() (available int, registered int)
+}

Знам, че е малко късно да го променяш. Но все пак искам да ти обърна внимание на едно нещо.

Ето това парче код

for {
        message, ok := <-librarian.request
        if ok {
                isbn := message.GetISBN()
                requestType := message.GetType()
                switch requestType {
                case BorrowBook:
                        libraryResponse := librarian.borrowBook(isbn)
                        librarian.response <- &libraryResponse
                case ReturnBook:
                        libraryResponse := librarian.returnBook(isbn)
                        librarian.response <- &libraryResponse
                case GetAvailability:
                        libraryResponse := librarian.getAvailability(isbn)
                        librarian.response <- &libraryResponse
                default:
                        librarian.response <- &CoolLibraryResponse{book: nil,
                                err: errors.New("Невалидна заявка")}
                }
        } else {
                break
        }
}

Би било много по - ясно написано като

for message := range librarian.request {
        isbn := message.GetISBN()
        requestType := message.GetType()
        switch requestType {
        case BorrowBook:
                libraryResponse := librarian.borrowBook(isbn)
                librarian.response <- &libraryResponse
        case ReturnBook:
                libraryResponse := librarian.returnBook(isbn)
                librarian.response <- &libraryResponse
        case GetAvailability:
                libraryResponse := librarian.getAvailability(isbn)
                librarian.response <- &libraryResponse
        default:
                librarian.response <- &CoolLibraryResponse{book: nil,
                        err: errors.New("Невалидна заявка")}
        }
}

Моето лично правило е, че ако забележа в кода си регион с 4-5 идентации, то значи трябва да го огледам много внимателно дали не правя нещо по - сложно от колкото може да е.

Ще ми трябва малко повече четене за да разбера къде имаш race condition или безкрайно зацикляне. Но изглежда, че има нещо такова.