Skip to content
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

Feature: PDU SubmitWindow with; MaxWindowSize option, ExpectedResponse handler, ExpiredPdus handler and NoRespPdu OnClose handler #134

Merged
merged 46 commits into from
Jun 15, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
c9a106c
this commit contains a concurrent map to keep track of request and re…
laduchesneau Feb 2, 2024
43f9add
storing the window(map) in the transceivable, so it can be reset on r…
laduchesneau Feb 2, 2024
d642365
adding logic to empty pdu cache after certain amount of time, will no…
laduchesneau Feb 3, 2024
0a73c3e
adding example
laduchesneau Feb 3, 2024
e0dbb09
remove handlePdu in new example
laduchesneau Feb 3, 2024
99827cf
move get window size to the session, this will revert the break in Tr…
laduchesneau Feb 3, 2024
215fb94
the new feature will have its own sub config, to better control if th…
laduchesneau Feb 3, 2024
7de1ae6
added comments to the new settings
laduchesneau Feb 3, 2024
7455655
move Request & Response types to gosmpp package in types.go
laduchesneau Feb 3, 2024
8966ec8
separating example into two diff examples, to show how to use new win…
laduchesneau Feb 4, 2024
2478683
fix concurrent-map issue when sending responses
laduchesneau Feb 4, 2024
de6f873
fix converage
laduchesneau Feb 4, 2024
f43006c
making the code in receivable more readable and fix comment
laduchesneau Feb 4, 2024
39fadfb
adding some test for ALlPDU
laduchesneau Feb 4, 2024
cd64186
adding some test
laduchesneau Feb 4, 2024
6a882e1
fix linter
laduchesneau Feb 4, 2024
3229152
removing check for setting.response != nil, the setting is always set
laduchesneau Feb 4, 2024
385bb02
Revert "removing check for setting.response != nil, the setting is al…
laduchesneau Feb 4, 2024
9ee1db7
remove the transmitter/receiver start to its on function for testing …
laduchesneau Feb 5, 2024
4da5383
added more test
laduchesneau Feb 5, 2024
571922f
added correct setting for WindowSize test
laduchesneau Feb 5, 2024
8a2e892
fix linter: remove unused sleep
laduchesneau Feb 5, 2024
c4d047e
adding test for autorespond
laduchesneau Feb 5, 2024
f966873
added handler to get all PDUs in the window store on bind close
laduchesneau Feb 5, 2024
2aa1fb4
only PDU that return true when CanResponse is called, that included c…
laduchesneau Feb 5, 2024
8f53a4c
separating the cleanup part into its own function
laduchesneau Feb 27, 2024
cda253c
ordered imports
laduchesneau Feb 27, 2024
d3f03b0
now using interface for store/cache
laduchesneau Feb 28, 2024
56900f5
adding missing code from last commit
laduchesneau Feb 28, 2024
558f2d2
reformation and add context.TODO, until I find the correct solution, …
laduchesneau Feb 28, 2024
9acc10a
add default store using bigcache
laduchesneau Mar 2, 2024
7cf7fd8
add missing return values for custom store
laduchesneau Mar 2, 2024
e1162eb
default store now uses concurrent-map
laduchesneau Mar 2, 2024
1217bb3
increase sleep time to avoid race condition with rebind
laduchesneau Mar 2, 2024
4fb5738
revert enquire_link timeouts, this should resolve race condition
laduchesneau Mar 2, 2024
e7f630f
the store cleanup will now run in transceivable and has a return bool…
laduchesneau Mar 3, 2024
c08e09a
updated example to new OnExpiredPduRequest return value
laduchesneau Mar 3, 2024
5a66e89
Merge branch 'master' into add_window_setting
laduchesneau Mar 21, 2024
706b08c
add a store access timeout value in ms, now support WithRequestStore …
laduchesneau Mar 21, 2024
78f2ef6
Merge branch 'master' into add_window_setting
laduchesneau Jun 10, 2024
f11c218
updating to latest experimental module
laduchesneau Jun 10, 2024
605de8f
fix custom example with mandatory settings
laduchesneau Jun 10, 2024
196b967
code cleanup, better names and some comments added
laduchesneau Jun 12, 2024
3fec633
added return errors from some functions in the RequestStore interface
laduchesneau Jun 12, 2024
31f1a9e
ignoring error handling for Delete for receivable and transceivable, …
laduchesneau Jun 12, 2024
00ca852
fix defer statement to be executed before running loop,
laduchesneau Jun 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func newBindRequest(s Auth, bindingType pdu.BindingType, addressRange pdu.Addres
// Connector is connection factory interface.
type Connector interface {
Connect() (conn *Connection, err error)
GetBindType() pdu.BindingType
}

type connector struct {
Expand All @@ -56,6 +57,10 @@ type connector struct {
addressRange pdu.AddressRange
}

func (c *connector) GetBindType() pdu.BindingType {
return c.bindingType
}

func (c *connector) Connect() (conn *Connection, err error) {
conn, err = connect(c.dialer, c.auth.SMSC, newBindRequest(c.auth, c.bindingType, c.addressRange))
return
Expand Down
19 changes: 19 additions & 0 deletions connect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,22 @@ func TestBindingSMSC_Error(t *testing.T) {
checker(t, TRXConnector(NonTLSDialer, auth))
})
}

func TestBindingType(t *testing.T) {
auth := Auth{SMSC: smscAddr, SystemID: "invalid"}

t.Run("TX", func(t *testing.T) {
c := TXConnector(NonTLSDialer, auth)
require.Equal(t, c.GetBindType(), pdu.Transmitter)
})

t.Run("RX", func(t *testing.T) {
c := RXConnector(NonTLSDialer, auth)
require.Equal(t, c.GetBindType(), pdu.Receiver)
})

t.Run("TRX", func(t *testing.T) {
c := TRXConnector(NonTLSDialer, auth)
require.Equal(t, c.GetBindType(), pdu.Transceiver)
})
}
169 changes: 169 additions & 0 deletions example/transeiver_with_custom_store/CustomStore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package main

import (
"bytes"
"context"
"encoding/gob"
"errors"
"fmt"
"github.com/allegro/bigcache/v3"
"github.com/linxGnu/gosmpp/pdu"
"strconv"
"time"

"github.com/linxGnu/gosmpp"
)

// This is a just an example how to implement a custom store.
//
// Your implementation must be concurrency safe
//
// In this example we use bigcache https://github.com/allegro/bigcache
// Warning:
// - This is just an example and should be tested before using in production
// - We are serializing with gob, some field cannot be serialized for simplicity
// - We recommend you implement your own serialization/deserialization if you choose to use bigcache

type CustomStore struct {
store *bigcache.BigCache
}

func NewCustomStore() CustomStore {
cache, _ := bigcache.New(context.Background(), bigcache.DefaultConfig(30*time.Second))
return CustomStore{
store: cache,
}
}

func (s CustomStore) Set(ctx context.Context, request gosmpp.Request) {
for {
laduchesneau marked this conversation as resolved.
Show resolved Hide resolved
select {
case <-ctx.Done():
fmt.Println("Task cancelled")
return
default:
b, _ := serialize(request)
_ = s.store.Set(strconv.Itoa(int(request.PDU.GetSequenceNumber())), b)
return
}
}
}

func (s CustomStore) Get(ctx context.Context, sequenceNumber int32) (gosmpp.Request, bool) {
for {
select {
case <-ctx.Done():
fmt.Println("Task cancelled")
return gosmpp.Request{}, false
default:
bRequest, err := s.store.Get(strconv.Itoa(int(sequenceNumber)))
if err != nil {
return gosmpp.Request{}, false
}
request, err := deserialize(bRequest)
if err != nil {
return gosmpp.Request{}, false
}
return request, true
}
}
}

func (s CustomStore) List(ctx context.Context) []gosmpp.Request {
var requests []gosmpp.Request
for {
select {
case <-ctx.Done():
return requests
default:
it := s.store.Iterator()
for it.SetNext() {
value, err := it.Value()
if err != nil {
return requests
}
request, _ := deserialize(value.Value())
requests = append(requests, request)
}
return requests
}
}
}

func (s CustomStore) Delete(ctx context.Context, sequenceNumber int32) {
for {
select {
case <-ctx.Done():
return
default:
_ = s.store.Delete(strconv.Itoa(int(sequenceNumber)))
return
}
}
}

func (s CustomStore) Clear(ctx context.Context) {
for {
select {
case <-ctx.Done():
return
default:
_ = s.store.Reset()
return
}
}
}

func (s CustomStore) Length(ctx context.Context) int {
for {
select {
case <-ctx.Done():
return -1

default:
return s.store.Len()
}
}
}

func serialize(request gosmpp.Request) ([]byte, error) {
buf := pdu.NewBuffer(make([]byte, 0, 64))
request.PDU.Marshal(buf)
b := bytes.Buffer{}
e := gob.NewEncoder(&b)
err := e.Encode(requestGob{
Pdu: buf.Bytes(),
TimeSent: time.Time{},
})
if err != nil {
return b.Bytes()[:], errors.New("serialization failed")
}
return b.Bytes(), nil
}

func deserialize(bRequest []byte) (request gosmpp.Request, err error) {
r := requestGob{}
b := bytes.Buffer{}
_, err = b.Write(bRequest)
if err != nil {
return request, errors.New("deserialization failed")
}
d := gob.NewDecoder(&b)
err = d.Decode(&r)
if err != nil {
return request, errors.New("deserialization failed")
}
p, err := pdu.Parse(bytes.NewReader(r.Pdu))
if err != nil {
return gosmpp.Request{}, err
}
return gosmpp.Request{
PDU: p,
TimeSent: r.TimeSent,
}, nil
}

type requestGob struct {
Pdu []byte
TimeSent time.Time
}
Loading
Loading