Google Docs
大家好,我是皮丘。 請先看過第一週的影片之後再來回應,因為第一週影片未來應該會下架。
突然發現這個專案好像還沒有設定 CI / CD ?
預定修改的程式碼為 passwd.go passwd_test.go 兩個檔案,請參考 <https://github.com/ptt/pttbbs/blob/master/include/pttstruct.h|https://github.com/ptt/pttbbs/blob/master/include/pttstruct.h> 裡面的 userec 結構將 testcase 裡面的 passwd 檔案的內容解出來並做成測試檔。
#33 定義發文所需要的 Connector Interface Method
目前在 <https://github.com/PichuChen/go-bbs/blob/d49298349281c75edd721caece6db88744df7dba/bbs.go#L89|go-bbs/bbs.go> Line 89 in </PichuChen/go-bbs/commit/d49298349281c75edd721caece6db88744df7dba|d492983> 有定義Connector ,但目前的 Connector 只有讀取的功能,需要定義有寫入功能的 BBS Driver 要實作哪些東西。 方向上有兩種,一種是在原有的 Connector 新增 Method 第二種是定義新的Interface 可能叫做 WritableConnector 或是 BBSWriter 之類的,然後去定義這個 Interface, 使用上就是檢查如果這個 Driver 沒有實作某個 Connector Interface 的話,就是視為這個 BBS Driver 不支援某類型的功能。
雖然套件名稱是 Cache 但實際上是用來讀取 SHM 的套件 初步想法是這樣,目前在測試環境的 SHM 已經被打包下來了,約 44MB, 因此在 Parsing 的時候透過 mmap 的 System call 就能夠讀入記憶體了。 但是根據每個BBS編譯設定不同,欄位所在的記憶體位置也會不同,因此這部分需要動態算出位置,算出位置後下一步就能取得該位置的資料或是將資料寫入該位址。 如果回傳的是 `[]byte` byte slice 的話,那利用者就能自由的讀取和修改某段記憶體位置了(還不用copy) <https://play.golang.org/p/vEUqcyc5g94|https://play.golang.org/p/vEUqcyc5g94> 第一階段因為方便測試,所以用 mmap 打開測試資料,然後上線前改成透過 cgo 開啟 system V SHM 的版本。 大概是這樣的計畫,看有沒有人有興趣或是其他意見。
Ptt-official-app/go-openbbsmiddleware
go implementation of openbbs-middleware.
devptt.site
Web site created using create-react-app
根據 PTT APP 規劃,後台應該要提供找尋同樣作者的功能 預定透過 /v1/boards/{{board_id}}/articles API 實作 修改 PTT 後端系統協定增加參數 ?author={{search_author_id}} 來完成 初期演算法先以 O(n) 的演算法進行實作即可, n 為某看板文章數量。
Reference to <https://github.com/Ptt-official-app/Ptt-backend/pull/11|#11> • 刪除章節號碼,避免日後調整順序需要改動所有的章節號碼 • TODO: 使用 Makefile 與 shell script 自動化測試伺服器靜態資料與配置設定檔與專案編譯執行過程
``` package shm //#include "shm.h" import "C" import ( "os" "reflect" "unsafe" "<http://github.com/Ptt-official-app/go-pttbbs/types|github.com/Ptt-official-app/go-pttbbs/types>" log "<http://github.com/sirupsen/logrus|github.com/sirupsen/logrus>" ) func CreateShm(key types.Key_t, size types.Size_t, isUseHugeTlb bool) (shmid int, shmaddr unsafe.Pointer, isNew bool, err error) { flags := 0600 | IPC_CREAT | IPC_EXCL if isUseHugeTlb { flags |= SHM_HUGETLB } shmid, err = shmget(key, size, flags) log.Debugf("shm.CreateShm: after 1st shmget: shmid: %v err: (%v/%v)", shmid, err, reflect.TypeOf(err)) isEExist := false if os.IsExist(err) { isEExist = true flags = 0600 | IPC_CREAT if isUseHugeTlb { flags |= SHM_HUGETLB } shmid, err = shmget(key, size, flags) log.Debugf("shm.CreateShm: after 2nd shmget: shmid: %v err: (%v/%v)", shmid, err, reflect.TypeOf(err)) } if shmid < 0 { log.Errorf("shm.CreateShm: unable to create shm: key: %v size: %v", key, size) return shmid, nil, false, err } shmaddr, err = shmat(shmid, nil, 0) log.Infof("shm.CreateShm: after shmat: shmaddr: %v e: %v", shmaddr, err) if err != nil { return -1, nil, false, err } return shmid, shmaddr, !isEExist, nil } func OpenShm(key types.Key_t, size types.Size_t, is_usehugetlb bool) (shmid int, shmaddr unsafe.Pointer, err error) { flags := 0 if is_usehugetlb { flags |= SHM_HUGETLB } shmid, err = shmget(key, size, flags) if err != nil { log.Errorf("shm.OpenShm: unable to create shm: key: %v size: %v", key, size) return shmid, nil, err } shmaddr, err = shmat(shmid, nil, 0) if err != nil { return -1, nil, err } return shmid, shmaddr, nil } func CloseShm(shmid int, shmaddr unsafe.Pointer) (err error) { cret, err := C.shmdt(shmaddr) log.Infof("shm.CloseShm: After detach shm: shmaddr: %v ret: %v err: %v", shmaddr, cret, err) if err != nil { return err } cret, err = C.shmctl(C.int(shmid), C.IPC_RMID, nil) log.Infof("shm.CloseShm: After close shm: shmaddr: %v ret: %v, err: %v", shmaddr, cret, err) if int(cret) < 0 { return ErrUnableToCloseShm } return nil } func ReadAt(shmaddr unsafe.Pointer, offset int, size uintptr, outptr unsafe.Pointer) { C.readwrapper(outptr, shmaddr, C.int(offset), C.ulong(size)) } func WriteAt(shmaddr unsafe.Pointer, offset int, size uintptr, inptr unsafe.Pointer) { C.writewrapper(shmaddr, C.int(offset), inptr, C.ulong(size)) } func IncUint32(shmaddr unsafe.Pointer, offset int) { C.incuint32wrapper(shmaddr, C.int(offset)) } func SetOrUint32(shmaddr unsafe.Pointer, offset int, flag uint32) { C.set_or_uint32wrapper(shmaddr, C.int(offset), C.uint(flag)) } func InnerSetInt32(shmaddr unsafe.Pointer, offsetSrc int, offsetDst int) { C.innerset_int32wrapper(shmaddr, C.int(offsetSrc), C.int(offsetDst)) } func Memset(shmaddr unsafe.Pointer, offset int, c byte, size uintptr) { C.memsetwrapper(shmaddr, C.int(offset), C.uchar(c), C.ulong(size)) } func SetBCACHEPTR(shmaddr unsafe.Pointer, offset int) { C.set_bcacheptr(shmaddr, C.int(offset)) } func QsortCmpBoardName(shmaddr unsafe.Pointer, offset int, n uint32) { C.qsort_cmpboardname_wrapper(shmaddr, C.int(offset), C.ulong(n)) } func QsortCmpBoardClass(shmaddr unsafe.Pointer, offset int, n uint32) { C.qsort_cmpboardclass_wrapper(shmaddr, C.int(offset), C.ulong(n)) } func shmget(key types.Key_t, size types.Size_t, shmflg int) (int, error) { cshmid, err := C.shmget(C.int(key), C.ulong(size), C.int(shmflg)) shmid := int(cshmid) if shmid < 0 { log.Errorf("unable to shmget: shmid: %v e: %v", shmid, err) } return shmid, err } func shmat(shmid int, shmaddr unsafe.Pointer, shmflg int) (unsafe.Pointer, error) { newShmAddr, err := C.shmat(C.int(shmid), shmaddr, C.int(shmflg)) if err != nil { return nil, err } return newShmAddr, nil } ```
*實作細節 / Details of Implement* 實作 PTT 很重要的發文功能 *API 細節* *Request* • Method: `POST` • Path: `/v1/boards/{{board_id}}/articles` • Body: ``` { "action": "add_article", "title": {{title}}, "article": {{article}} } ``` *Response* • Status: `200` • Body: ``` { "data": { "raw": {{raw_text}}, "parsed": { "is_header_modified": {{is_header_modified}}, "author_id": {{author_id}}, "author_name": {{author_name}}, "title": {{title}}, "post_time": {{post_time}}, "board_name": {{board_name}}, "text": { "text": {{text}}, "color_map": {{text_color_map}} }, "signature": { "text": {{signature_text}}, "color_map": {{signature_color_map}} }, "sender_info": { "site": {{sender_site}}, "ip_address": {{sender_ip_address}}, "ip_country": {{sender_ip_country}}, }, "edit_records": [{{edit_record}}], "push_records": [ { "type": {{push_record.type}}, "id": {{push_record.pusher_id}}, "ip_address": {{push_record.pusher_ip}}, "text": {{push_record.type}}, "time": {{push_record.time}}, } ] } } } ``` *期程 / Schedule* • 討論時間: 一週以內(2/7 前) • 實作時間: 待訂 • 確認時間: 待訂 *相關文件 / Documents* <https://docs.google.com/document/d/18DsZOyrlr5BIl2kKxZH7P2QxFLG02xL2SO0PzVHVY3k/edit#heading=h.o33bv47r1a5a|https://docs.google.com/document/d/18DsZOyrlr5BIl2kKxZH7P2QxFLG02xL2SO0PzVHVY3k/edit#heading=h.o33bv47r1a5a>